diff --git a/.gitignore b/.gitignore index 2df91c0..e52f815 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,20 @@ .idea/ go.sum +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# IDE config +.idea +.vscode + +bench.txt diff --git a/pkg/errors/code/define.go b/errors/code/define.go similarity index 100% rename from pkg/errors/code/define.go rename to errors/code/define.go diff --git a/pkg/errors/code/messsage.go b/errors/code/messsage.go similarity index 100% rename from pkg/errors/code/messsage.go rename to errors/code/messsage.go diff --git a/pkg/errors/easy_func.go b/errors/easy_func.go similarity index 99% rename from pkg/errors/easy_func.go rename to errors/easy_func.go index e970175..caca3b1 100644 --- a/pkg/errors/easy_func.go +++ b/errors/easy_func.go @@ -1,7 +1,7 @@ package error import ( - "code.30cm.net/wanderland/library-go/pkg/errors/code" + "code.30cm.net/wanderland/library-go/errors/code" "errors" "fmt" "strings" diff --git a/pkg/errors/easy_func_test.go b/errors/easy_func_test.go similarity index 99% rename from pkg/errors/easy_func_test.go rename to errors/easy_func_test.go index 8806b10..391f477 100644 --- a/pkg/errors/easy_func_test.go +++ b/errors/easy_func_test.go @@ -1,7 +1,7 @@ package error import ( - "code.30cm.net/wanderland/library-go/pkg/errors/code" + "code.30cm.net/wanderland/library-go/errors/code" "context" "errors" "fmt" diff --git a/pkg/errors/errors.go b/errors/errors.go similarity index 86% rename from pkg/errors/errors.go rename to errors/errors.go index 682bfd6..7aa6407 100644 --- a/pkg/errors/errors.go +++ b/errors/errors.go @@ -1,17 +1,17 @@ package error import ( + code2 "code.30cm.net/wanderland/library-go/errors/code" "errors" "fmt" "net/http" - "code.30cm.net/wanderland/library-go/pkg/errors/code" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) // Scope 全域變數應由服務或模組設置 -var Scope = code.Unset +var Scope = code2.Unset // Err 6 碼,服務 2, 大類 2, 詳細錯誤 2 type Err struct { @@ -60,7 +60,7 @@ func (e *Err) Category() uint32 { // Scope 私有屬性 "scope" 的 getter 函數 func (e *Err) Scope() uint32 { if e == nil { - return code.Unset + return code2.Unset } return e.scope @@ -72,7 +72,7 @@ func (e *Err) CodeStr() string { return "00000" } - if e.Category() == code.CatGRPC { + if e.Category() == code2.CatGRPC { return fmt.Sprintf("%d%04d", e.Scope(), e.Category()+e.Code()) } @@ -82,7 +82,7 @@ func (e *Err) CodeStr() string { // Code 私有屬性 "code" 的 getter 函數 func (e *Err) Code() uint32 { if e == nil { - return code.OK + return code2.OK } return e.code @@ -93,7 +93,7 @@ func (e *Err) FullCode() uint32 { return 0 } - if e.Category() == code.CatGRPC { + if e.Category() == code2.CatGRPC { return e.Scope()*10000 + e.Category() + e.Code() } @@ -102,30 +102,30 @@ func (e *Err) FullCode() uint32 { // HTTPStatus 返回對應的 HTTP 狀態碼 func (e *Err) HTTPStatus() int { - if e == nil || e.Code() == code.OK { + if e == nil || e.Code() == code2.OK { return http.StatusOK } // 根據 code 判斷狀態碼 switch e.Code() { - case code.ResourceInsufficient: + case code2.ResourceInsufficient: // 400 return http.StatusBadRequest - case code.Unauthorized, code.InsufficientPermission: + case code2.Unauthorized, code2.InsufficientPermission: // 401 return http.StatusUnauthorized - case code.InsufficientQuota: + case code2.InsufficientQuota: // 402 return http.StatusPaymentRequired - case code.InvalidPosixTime, code.Forbidden: + case code2.InvalidPosixTime, code2.Forbidden: // 403 return http.StatusForbidden - case code.ResourceNotFound: + case code2.ResourceNotFound: // 404 return http.StatusNotFound - case code.ResourceAlreadyExist, code.InvalidResourceState: + case code2.ResourceAlreadyExist, code2.InvalidResourceState: // 409 return http.StatusConflict - case code.NotValidImplementation: + case code2.NotValidImplementation: // 501 return http.StatusNotImplemented default: @@ -133,7 +133,7 @@ func (e *Err) HTTPStatus() int { // 根據 category 判斷狀態碼 switch e.Category() { - case code.CatInput: + case code2.CatInput: return http.StatusBadRequest default: // 如果沒有符合的條件,返回狀態碼 500 @@ -148,7 +148,7 @@ func (e *Err) GeneralError() string { return "" } - errStr, ok := code.CatToStr[e.Category()] + errStr, ok := code2.CatToStr[e.Category()] if !ok { return "" } @@ -210,7 +210,7 @@ func NewErr(scope, category, detail uint32, msg string) *Err { // NewGRPCErr 創建新的 gRPC Err func NewGRPCErr(scope, detail uint32, msg string) *Err { return &Err{ - category: code.CatGRPC, + category: code2.CatGRPC, code: detail, scope: scope, msg: msg, diff --git a/pkg/errors/errors_test.go b/errors/errors_test.go similarity index 75% rename from pkg/errors/errors_test.go rename to errors/errors_test.go index 8adef4d..c1d5643 100644 --- a/pkg/errors/errors_test.go +++ b/errors/errors_test.go @@ -1,7 +1,7 @@ package error import ( - "code.30cm.net/wanderland/library-go/pkg/errors/code" + code2 "code.30cm.net/wanderland/library-go/errors/code" "errors" "fmt" "net/http" @@ -17,7 +17,7 @@ func TestCode_GivenNilReceiver_CodeReturnOK_CodeStrReturns00000(t *testing.T) { var e *Err = nil // act & assert - assert.Equal(t, code.OK, e.Code()) + assert.Equal(t, code2.OK, e.Code()) assert.Equal(t, "00000", e.CodeStr()) assert.Equal(t, "", e.Error()) } @@ -103,8 +103,8 @@ func TestGeneralError_GivenNotExistCat_ShouldReturnEmptyString(t *testing.T) { func TestGeneralError_GivenCatDB_ShouldReturnDBError(t *testing.T) { // setup - e := Err{category: code.CatDB} - catErrStr := code.CatToStr[code.CatDB] + e := Err{category: code2.CatDB} + catErrStr := code2.CatToStr[code2.CatDB] // act & assert assert.Equal(t, catErrStr, e.GeneralError()) @@ -112,13 +112,13 @@ func TestGeneralError_GivenCatDB_ShouldReturnDBError(t *testing.T) { func TestError_GivenEmptyMsg_ShouldReturnCatGeneralErrorMessage(t *testing.T) { // setup - e := Err{category: code.CatDB, msg: ""} + e := Err{category: code2.CatDB, msg: ""} // act errMsg := e.Error() // assert - assert.Equal(t, code.CatToStr[code.CatDB], errMsg) + assert.Equal(t, code2.CatToStr[code2.CatDB], errMsg) } func TestError_GivenMsg_ShouldReturnGiveMsg(t *testing.T) { @@ -269,20 +269,20 @@ func TestErr_HTTPStatus(t *testing.T) { want int }{ {name: "nil error", err: nil, want: http.StatusOK}, - {name: "invalid measurement id", err: &Err{category: code.CatResource, code: code.InvalidMeasurementID}, want: http.StatusInternalServerError}, - {name: "resource already exists", err: &Err{category: code.CatResource, code: code.ResourceAlreadyExist}, want: http.StatusConflict}, - {name: "invalid resource state", err: &Err{category: code.CatResource, code: code.InvalidResourceState}, want: http.StatusConflict}, - {name: "invalid posix time", err: &Err{category: code.CatAuth, code: code.InvalidPosixTime}, want: http.StatusForbidden}, - {name: "unauthorized", err: &Err{category: code.CatAuth, code: code.Unauthorized}, want: http.StatusUnauthorized}, - {name: "db error", err: &Err{category: code.CatDB, code: code.DBError}, want: http.StatusInternalServerError}, - {name: "insufficient permission", err: &Err{category: code.CatResource, code: code.InsufficientPermission}, want: http.StatusUnauthorized}, - {name: "resource insufficient", err: &Err{category: code.CatResource, code: code.ResourceInsufficient}, want: http.StatusBadRequest}, - {name: "invalid format", err: &Err{category: code.CatInput, code: code.InvalidFormat}, want: http.StatusBadRequest}, - {name: "resource not found", err: &Err{code: code.ResourceNotFound}, want: http.StatusNotFound}, - {name: "ok", err: &Err{code: code.OK}, want: http.StatusOK}, - {name: "not valid implementation", err: &Err{category: code.CatInput, code: code.NotValidImplementation}, want: http.StatusNotImplemented}, - {name: "forbidden", err: &Err{category: code.CatAuth, code: code.Forbidden}, want: http.StatusForbidden}, - {name: "insufficient quota", err: &Err{category: code.CatResource, code: code.InsufficientQuota}, want: http.StatusPaymentRequired}, + {name: "invalid measurement id", err: &Err{category: code2.CatResource, code: code2.InvalidMeasurementID}, want: http.StatusInternalServerError}, + {name: "resource already exists", err: &Err{category: code2.CatResource, code: code2.ResourceAlreadyExist}, want: http.StatusConflict}, + {name: "invalid resource state", err: &Err{category: code2.CatResource, code: code2.InvalidResourceState}, want: http.StatusConflict}, + {name: "invalid posix time", err: &Err{category: code2.CatAuth, code: code2.InvalidPosixTime}, want: http.StatusForbidden}, + {name: "unauthorized", err: &Err{category: code2.CatAuth, code: code2.Unauthorized}, want: http.StatusUnauthorized}, + {name: "db error", err: &Err{category: code2.CatDB, code: code2.DBError}, want: http.StatusInternalServerError}, + {name: "insufficient permission", err: &Err{category: code2.CatResource, code: code2.InsufficientPermission}, want: http.StatusUnauthorized}, + {name: "resource insufficient", err: &Err{category: code2.CatResource, code: code2.ResourceInsufficient}, want: http.StatusBadRequest}, + {name: "invalid format", err: &Err{category: code2.CatInput, code: code2.InvalidFormat}, want: http.StatusBadRequest}, + {name: "resource not found", err: &Err{code: code2.ResourceNotFound}, want: http.StatusNotFound}, + {name: "ok", err: &Err{code: code2.OK}, want: http.StatusOK}, + {name: "not valid implementation", err: &Err{category: code2.CatInput, code: code2.NotValidImplementation}, want: http.StatusNotImplemented}, + {name: "forbidden", err: &Err{category: code2.CatAuth, code: code2.Forbidden}, want: http.StatusForbidden}, + {name: "insufficient quota", err: &Err{category: code2.CatResource, code: code2.InsufficientQuota}, want: http.StatusPaymentRequired}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/errors/readme.md b/errors/readme.md similarity index 100% rename from pkg/errors/readme.md rename to errors/readme.md diff --git a/go.work b/go.work new file mode 100644 index 0000000..bfbbde3 --- /dev/null +++ b/go.work @@ -0,0 +1,5 @@ +go 1.22 + +use ( + ./errors +) diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..0d98fbb --- /dev/null +++ b/readme.md @@ -0,0 +1,99 @@ +# golang-common + +## Current modules + +| module | latest version | +|--------------------------------------------------------|----------------| +| [error](errors) | v1.0.0 | + + +## 如何新增Module + +假設新增一個module叫 monitoring/grafana + +- init + +```bash +mkdir -p monitoring/grafana +cd ./monitoring/grafana +go mod init yt.com/backend/common.git/monitoring/grafana +go work use ./monitoring/grafana +``` + +- befor commit + +建議測試覆蓋率盡量達到80% + +```bash +before-commit-check +``` + +- commit + +```bash +git add ./monitoring/grafana +git commit -m "feat: add monitoring/grafana module" +git tag "monitoring/grafana/v1.0.0" +git push origin monitoring/grafana/v1.0.0 +``` + +- launch merge request and codereview + +## 如何使用私有Module + +強制git使用ssh方式而不是https: + +```bash +git config --global --add url."git@code.30cm.net:".insteadOf "https://code.30cm.net/" + +# 檢查語法 +vim ~/.gitconfig +``` + +設定go env + +```bash +export GOPRIVATE="code.30cm.net" +``` + +產生ssh-key +請參考 [github ssh](https://docs.github.com/en/authentication/connecting-to-github-with-ssh) , [gitlab ssh](https://docs.gitlab.com/ee/user/ssh.html) + +add ssh key to the ssh-agent +請參考 [Adding your SSH key to the ssh-agent](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent#adding-your-ssh-key-to-the-ssh-agent) + +```bash +$ eval "$(ssh-agent -s)" +> Agent pid 59566 +``` + +```bash +$ touch ~/.ssh/config +``` + +``` +Host code.30cm.net + Hostname code.30cm.net + User Daniel.W + IdentityFile ~/.ssh/id_rsa +``` + +```bash +$ ssh-add --apple-use-keychain ~/.ssh/id_ed25519 +``` + +使用 yt.com domain, git clone repo + +```bash +git clone git@code.30cm.net:backend/layout-template.git +``` + +在自己repo底下執行: + +```bash +go clean -modcache +go mod tidy + +or +go get -x yt.com/backend/common.git/transport/http/health@1.0.0 +```