Skip to content

Commit eea27ad

Browse files
authored
Add errors helper package (#1)
Signed-off-by: Emruz Hossain <[email protected]>
1 parent d42c494 commit eea27ad

14 files changed

+753
-0
lines changed

.github/dependabot.yml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "gomod"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
8+
- package-ecosystem: "docker"
9+
directory: "/"
10+
schedule:
11+
interval: "weekly"
12+
13+
- package-ecosystem: "github-actions"
14+
directory: "/"
15+
schedule:
16+
interval: "weekly"

.github/release-drafter.yml

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
categories:
2+
- title: '🚀 Features'
3+
labels:
4+
- 'feature'
5+
- 'feat'
6+
- 'enhancement'
7+
- title: '🐛 Bug Fixes'
8+
labels:
9+
- 'fix'
10+
- 'bugfix'
11+
- 'bug'
12+
- title: '🧰 Maintenance'
13+
labels:
14+
- 'chore'
15+
- 'dependencies'
16+
template: |
17+
# What’s Changed
18+
19+
$CHANGES
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Merged to Main
2+
on:
3+
pull_request:
4+
types: [ closed ]
5+
branches: [ 'main' ]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
MergedtoMain:
12+
if: github.event.pull_request.merged == true
13+
name: Merged to Main
14+
runs-on: ubuntu-latest
15+
permissions:
16+
# write permission is required to create a github release
17+
contents: write
18+
pull-requests: write
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v4
22+
23+
- name: Extract build info
24+
id: extract_build_info
25+
run: |
26+
echo "commit_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
27+
28+
- name: Update Release Draft
29+
uses: release-drafter/release-drafter@v6
30+
with:
31+
disable-autolabeler: true
32+
commitish: main
33+
publish: false
34+
env:
35+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/pr-workflow.yaml

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: PR Workflow
2+
on:
3+
pull_request:
4+
types: [ synchronize, opened, reopened]
5+
branches: [ 'main' ]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
linter:
12+
name: Linter
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
18+
- uses: actions/setup-go@v5
19+
with:
20+
go-version: '^1.23'
21+
cache: false
22+
23+
- name: Check Go Formatting
24+
run: |
25+
files=$(gofmt -l .) && echo $files && [ -z "$files" ]
26+
27+
- name: Golang CI Lint
28+
uses: golangci/golangci-lint-action@v6
29+
30+
unit-tests:
31+
name: Unit Tests
32+
runs-on: ubuntu-latest
33+
steps:
34+
- name: Checkout
35+
uses: actions/checkout@v4
36+
37+
- uses: actions/setup-go@v5
38+
with:
39+
go-version: '^1.23'
40+
41+
- name: Unit tests
42+
run: |
43+
make test_unit
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Release
2+
on:
3+
push:
4+
branches:
5+
- 'releases/**'
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
Release:
12+
name: Release Workflow
13+
runs-on: ubuntu-latest
14+
permissions:
15+
# write permission is required to create a github release
16+
contents: write
17+
pull-requests: write
18+
id-token: write # needed for cosign keyless signing with OIDC
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v4
22+
23+
- name: Extract build info
24+
id: extract_build_info
25+
run: |
26+
echo "tag=${GITHUB_REF##*/}" >> $GITHUB_OUTPUT
27+
echo "commit_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
28+
29+
- name: Tag Release
30+
shell: bash
31+
run: |
32+
git tag ${{ steps.extract_build_info.outputs.tag }}
33+
git push origin ${{ steps.extract_build_info.outputs.tag }}
34+
35+
- name: Publish Release Notes
36+
uses: release-drafter/release-drafter@v6
37+
with:
38+
disable-autolabeler: true
39+
commitish: ${{ github.ref }}
40+
tag: ${{ steps.extract_build_info.outputs.tag }}
41+
publish: true
42+
env:
43+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# If you prefer the allow list template instead of the deny list, see community template:
22
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
33
#
4+
# IDE files
5+
.idea/
6+
.vscode/
47
# Binaries for programs and plugins
8+
bin/
59
*.exe
610
*.exe~
711
*.dll

.golangci.yaml

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
run:
2+
timeout: 10m
3+
issues:
4+
exclude-files:
5+
- "generated.*\\.go$"
6+
linters:
7+
enable:
8+
- gci
9+
- goconst
10+
- gofmt
11+
- goimports
12+
- unparam
13+
- importas
14+
- bodyclose
15+
- containedctx
16+
- contextcheck
17+
- errorlint
18+
- nilerr
19+
- promlinter
20+
- sloglint
21+
- testifylint
22+
- unparam
23+
- usestdlibvars
24+
linters-settings:
25+
gci:
26+
sections:
27+
- standard # Standard section: captures all standard packages.
28+
- default # Default section: contains all imports that could not be matched to another section type.
29+
- prefix(github.com/qdrant) # Custom section: groups all imports with the specified Prefix.
30+
importas:
31+
alias:
32+
- pkg: ^k8s\.io/apimachinery/pkg/apis/(\w+)/(v[\w\d]+)$
33+
alias: $1$2

.pre-commit-config.yaml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
repos:
2+
- repo: https://github.com/golangci/golangci-lint
3+
rev: v1.55.2
4+
hooks:
5+
- id: golangci-lint-full
6+
- repo: https://github.com/tekwizely/pre-commit-golang
7+
rev: v1.0.0-rc.1
8+
hooks:
9+
- id: go-mod-tidy-repo
10+
- id: go-fmt
11+
- id: go-test-repo-mod

Makefile

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
## Location to install dependencies to
2+
LOCALBIN ?= $(shell pwd)/bin
3+
$(LOCALBIN):
4+
mkdir -p $(LOCALBIN)
5+
6+
## Tool Binaries
7+
GO_IMPORTS ?= $(LOCALBIN)/goimports
8+
GCI ?= $(LOCALBIN)/gci
9+
10+
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
11+
ifeq (,$(shell go env GOBIN))
12+
GOBIN=$(shell go env GOPATH)/bin
13+
else
14+
GOBIN=$(shell go env GOBIN)
15+
endif
16+
17+
# Setting SHELL to bash allows bash commands to be executed by recipes.
18+
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
19+
SHELL = /usr/bin/env bash -o pipefail
20+
.SHELLFLAGS = -ec
21+
22+
.PHONY: help
23+
help: ## Display this help.
24+
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
25+
26+
##@ Development
27+
28+
.PHONY: go_fmt
29+
go_fmt: ## Run go fmt against code.
30+
gofmt -w -s .
31+
32+
.PHONY: fmt_imports
33+
fmt_imports: $(GCI) ## Run goimports against code.
34+
$(GCI) write ./ --skip-generated -s standard -s default -s 'prefix(github.com/qdrant)'
35+
36+
.PHONY: fmt
37+
format: go_fmt fmt_imports ## Format the code.
38+
39+
fmt: format ## Format the code.
40+
41+
.PHONY: vet
42+
vet: ## Run go vet against code.
43+
go vet ./...
44+
45+
lint: $(GCI) ## Run linters.
46+
bash -c 'files=$$(gofmt -l .) && echo $$files && [ -z "$$files" ]'
47+
golangci-lint run
48+
49+
.PHONY: test_unit
50+
test_unit: ## Run unit tests.
51+
go test ./... -coverprofile cover.out
52+
53+
$(GO_IMPORTS): $(LOCALBIN)
54+
GOBIN=$(LOCALBIN) go install golang.org/x/tools/cmd/goimports@latest
55+
56+
$(GCI): $(LOCALBIN)
57+
GOBIN=$(LOCALBIN) go install github.com/daixiang0/gci@latest
58+
59+

examples/errors/main.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"log/slog"
7+
8+
errhelper "github.com/qdrant/go-commons/pkg/errors"
9+
)
10+
11+
func main() {
12+
// call some function that produces error
13+
err := someCodeProducesError()
14+
if err != nil {
15+
// log the error with context
16+
slog.Error(fmt.Sprintf("something went wrong: %s", err.Error()), errhelper.GetMetadata(err)...)
17+
}
18+
}
19+
20+
func someCodeProducesError() error {
21+
// root wrapper that include function name as context
22+
errMetadata := errhelper.Metadata{"function", "someCodeProducesError"}
23+
24+
// another block of code that can produce error
25+
err := doSomething()
26+
if err != nil {
27+
// wrap the error with additional context
28+
// the resulting error will include the context from root wrapper and this wrapper
29+
return errhelper.WithMetadata(err, errMetadata.Extend("key1", "value1")...)
30+
}
31+
32+
// this will only wrap error with root wrapper context
33+
return errhelper.WithMetadata(errors.New("foo"), errMetadata...)
34+
}
35+
36+
func doSomething() error {
37+
// simulate an error
38+
return errhelper.WithMetadata(
39+
errors.New("bar"),
40+
"function", "doSomething",
41+
"key2", "value2",
42+
)
43+
}

go.mod

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module github.com/qdrant/go-commons
2+
3+
go 1.24.0
4+
5+
require github.com/stretchr/testify v1.10.0
6+
7+
require (
8+
github.com/davecgh/go-spew v1.1.1 // indirect
9+
github.com/pmezard/go-difflib v1.0.0 // indirect
10+
gopkg.in/yaml.v3 v3.0.1 // indirect
11+
)

go.sum

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
6+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
7+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
8+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
9+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
10+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 commit comments

Comments
 (0)