feat: move folder
This commit is contained in:
parent
c65291893c
commit
1953246b44
|
@ -1,2 +1,20 @@
|
||||||
.idea/
|
.idea/
|
||||||
go.sum
|
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
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package error
|
package error
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.30cm.net/wanderland/library-go/pkg/errors/code"
|
"code.30cm.net/wanderland/library-go/errors/code"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
|
@ -1,7 +1,7 @@
|
||||||
package error
|
package error
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.30cm.net/wanderland/library-go/pkg/errors/code"
|
"code.30cm.net/wanderland/library-go/errors/code"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
|
@ -1,17 +1,17 @@
|
||||||
package error
|
package error
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
code2 "code.30cm.net/wanderland/library-go/errors/code"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.30cm.net/wanderland/library-go/pkg/errors/code"
|
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Scope 全域變數應由服務或模組設置
|
// Scope 全域變數應由服務或模組設置
|
||||||
var Scope = code.Unset
|
var Scope = code2.Unset
|
||||||
|
|
||||||
// Err 6 碼,服務 2, 大類 2, 詳細錯誤 2
|
// Err 6 碼,服務 2, 大類 2, 詳細錯誤 2
|
||||||
type Err struct {
|
type Err struct {
|
||||||
|
@ -60,7 +60,7 @@ func (e *Err) Category() uint32 {
|
||||||
// Scope 私有屬性 "scope" 的 getter 函數
|
// Scope 私有屬性 "scope" 的 getter 函數
|
||||||
func (e *Err) Scope() uint32 {
|
func (e *Err) Scope() uint32 {
|
||||||
if e == nil {
|
if e == nil {
|
||||||
return code.Unset
|
return code2.Unset
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.scope
|
return e.scope
|
||||||
|
@ -72,7 +72,7 @@ func (e *Err) CodeStr() string {
|
||||||
return "00000"
|
return "00000"
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Category() == code.CatGRPC {
|
if e.Category() == code2.CatGRPC {
|
||||||
return fmt.Sprintf("%d%04d", e.Scope(), e.Category()+e.Code())
|
return fmt.Sprintf("%d%04d", e.Scope(), e.Category()+e.Code())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ func (e *Err) CodeStr() string {
|
||||||
// Code 私有屬性 "code" 的 getter 函數
|
// Code 私有屬性 "code" 的 getter 函數
|
||||||
func (e *Err) Code() uint32 {
|
func (e *Err) Code() uint32 {
|
||||||
if e == nil {
|
if e == nil {
|
||||||
return code.OK
|
return code2.OK
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.code
|
return e.code
|
||||||
|
@ -93,7 +93,7 @@ func (e *Err) FullCode() uint32 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Category() == code.CatGRPC {
|
if e.Category() == code2.CatGRPC {
|
||||||
return e.Scope()*10000 + e.Category() + e.Code()
|
return e.Scope()*10000 + e.Category() + e.Code()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,30 +102,30 @@ func (e *Err) FullCode() uint32 {
|
||||||
|
|
||||||
// HTTPStatus 返回對應的 HTTP 狀態碼
|
// HTTPStatus 返回對應的 HTTP 狀態碼
|
||||||
func (e *Err) HTTPStatus() int {
|
func (e *Err) HTTPStatus() int {
|
||||||
if e == nil || e.Code() == code.OK {
|
if e == nil || e.Code() == code2.OK {
|
||||||
return http.StatusOK
|
return http.StatusOK
|
||||||
}
|
}
|
||||||
// 根據 code 判斷狀態碼
|
// 根據 code 判斷狀態碼
|
||||||
switch e.Code() {
|
switch e.Code() {
|
||||||
case code.ResourceInsufficient:
|
case code2.ResourceInsufficient:
|
||||||
// 400
|
// 400
|
||||||
return http.StatusBadRequest
|
return http.StatusBadRequest
|
||||||
case code.Unauthorized, code.InsufficientPermission:
|
case code2.Unauthorized, code2.InsufficientPermission:
|
||||||
// 401
|
// 401
|
||||||
return http.StatusUnauthorized
|
return http.StatusUnauthorized
|
||||||
case code.InsufficientQuota:
|
case code2.InsufficientQuota:
|
||||||
// 402
|
// 402
|
||||||
return http.StatusPaymentRequired
|
return http.StatusPaymentRequired
|
||||||
case code.InvalidPosixTime, code.Forbidden:
|
case code2.InvalidPosixTime, code2.Forbidden:
|
||||||
// 403
|
// 403
|
||||||
return http.StatusForbidden
|
return http.StatusForbidden
|
||||||
case code.ResourceNotFound:
|
case code2.ResourceNotFound:
|
||||||
// 404
|
// 404
|
||||||
return http.StatusNotFound
|
return http.StatusNotFound
|
||||||
case code.ResourceAlreadyExist, code.InvalidResourceState:
|
case code2.ResourceAlreadyExist, code2.InvalidResourceState:
|
||||||
// 409
|
// 409
|
||||||
return http.StatusConflict
|
return http.StatusConflict
|
||||||
case code.NotValidImplementation:
|
case code2.NotValidImplementation:
|
||||||
// 501
|
// 501
|
||||||
return http.StatusNotImplemented
|
return http.StatusNotImplemented
|
||||||
default:
|
default:
|
||||||
|
@ -133,7 +133,7 @@ func (e *Err) HTTPStatus() int {
|
||||||
|
|
||||||
// 根據 category 判斷狀態碼
|
// 根據 category 判斷狀態碼
|
||||||
switch e.Category() {
|
switch e.Category() {
|
||||||
case code.CatInput:
|
case code2.CatInput:
|
||||||
return http.StatusBadRequest
|
return http.StatusBadRequest
|
||||||
default:
|
default:
|
||||||
// 如果沒有符合的條件,返回狀態碼 500
|
// 如果沒有符合的條件,返回狀態碼 500
|
||||||
|
@ -148,7 +148,7 @@ func (e *Err) GeneralError() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
errStr, ok := code.CatToStr[e.Category()]
|
errStr, ok := code2.CatToStr[e.Category()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ func NewErr(scope, category, detail uint32, msg string) *Err {
|
||||||
// NewGRPCErr 創建新的 gRPC Err
|
// NewGRPCErr 創建新的 gRPC Err
|
||||||
func NewGRPCErr(scope, detail uint32, msg string) *Err {
|
func NewGRPCErr(scope, detail uint32, msg string) *Err {
|
||||||
return &Err{
|
return &Err{
|
||||||
category: code.CatGRPC,
|
category: code2.CatGRPC,
|
||||||
code: detail,
|
code: detail,
|
||||||
scope: scope,
|
scope: scope,
|
||||||
msg: msg,
|
msg: msg,
|
|
@ -1,7 +1,7 @@
|
||||||
package error
|
package error
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.30cm.net/wanderland/library-go/pkg/errors/code"
|
code2 "code.30cm.net/wanderland/library-go/errors/code"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -17,7 +17,7 @@ func TestCode_GivenNilReceiver_CodeReturnOK_CodeStrReturns00000(t *testing.T) {
|
||||||
var e *Err = nil
|
var e *Err = nil
|
||||||
|
|
||||||
// act & assert
|
// 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, "00000", e.CodeStr())
|
||||||
assert.Equal(t, "", e.Error())
|
assert.Equal(t, "", e.Error())
|
||||||
}
|
}
|
||||||
|
@ -103,8 +103,8 @@ func TestGeneralError_GivenNotExistCat_ShouldReturnEmptyString(t *testing.T) {
|
||||||
|
|
||||||
func TestGeneralError_GivenCatDB_ShouldReturnDBError(t *testing.T) {
|
func TestGeneralError_GivenCatDB_ShouldReturnDBError(t *testing.T) {
|
||||||
// setup
|
// setup
|
||||||
e := Err{category: code.CatDB}
|
e := Err{category: code2.CatDB}
|
||||||
catErrStr := code.CatToStr[code.CatDB]
|
catErrStr := code2.CatToStr[code2.CatDB]
|
||||||
|
|
||||||
// act & assert
|
// act & assert
|
||||||
assert.Equal(t, catErrStr, e.GeneralError())
|
assert.Equal(t, catErrStr, e.GeneralError())
|
||||||
|
@ -112,13 +112,13 @@ func TestGeneralError_GivenCatDB_ShouldReturnDBError(t *testing.T) {
|
||||||
|
|
||||||
func TestError_GivenEmptyMsg_ShouldReturnCatGeneralErrorMessage(t *testing.T) {
|
func TestError_GivenEmptyMsg_ShouldReturnCatGeneralErrorMessage(t *testing.T) {
|
||||||
// setup
|
// setup
|
||||||
e := Err{category: code.CatDB, msg: ""}
|
e := Err{category: code2.CatDB, msg: ""}
|
||||||
|
|
||||||
// act
|
// act
|
||||||
errMsg := e.Error()
|
errMsg := e.Error()
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
assert.Equal(t, code.CatToStr[code.CatDB], errMsg)
|
assert.Equal(t, code2.CatToStr[code2.CatDB], errMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestError_GivenMsg_ShouldReturnGiveMsg(t *testing.T) {
|
func TestError_GivenMsg_ShouldReturnGiveMsg(t *testing.T) {
|
||||||
|
@ -269,20 +269,20 @@ func TestErr_HTTPStatus(t *testing.T) {
|
||||||
want int
|
want int
|
||||||
}{
|
}{
|
||||||
{name: "nil error", err: nil, want: http.StatusOK},
|
{name: "nil error", err: nil, want: http.StatusOK},
|
||||||
{name: "invalid measurement id", err: &Err{category: code.CatResource, code: code.InvalidMeasurementID}, want: http.StatusInternalServerError},
|
{name: "invalid measurement id", err: &Err{category: code2.CatResource, code: code2.InvalidMeasurementID}, want: http.StatusInternalServerError},
|
||||||
{name: "resource already exists", err: &Err{category: code.CatResource, code: code.ResourceAlreadyExist}, want: http.StatusConflict},
|
{name: "resource already exists", err: &Err{category: code2.CatResource, code: code2.ResourceAlreadyExist}, want: http.StatusConflict},
|
||||||
{name: "invalid resource state", err: &Err{category: code.CatResource, code: code.InvalidResourceState}, 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: code.CatAuth, code: code.InvalidPosixTime}, want: http.StatusForbidden},
|
{name: "invalid posix time", err: &Err{category: code2.CatAuth, code: code2.InvalidPosixTime}, want: http.StatusForbidden},
|
||||||
{name: "unauthorized", err: &Err{category: code.CatAuth, code: code.Unauthorized}, want: http.StatusUnauthorized},
|
{name: "unauthorized", err: &Err{category: code2.CatAuth, code: code2.Unauthorized}, want: http.StatusUnauthorized},
|
||||||
{name: "db error", err: &Err{category: code.CatDB, code: code.DBError}, want: http.StatusInternalServerError},
|
{name: "db error", err: &Err{category: code2.CatDB, code: code2.DBError}, want: http.StatusInternalServerError},
|
||||||
{name: "insufficient permission", err: &Err{category: code.CatResource, code: code.InsufficientPermission}, want: http.StatusUnauthorized},
|
{name: "insufficient permission", err: &Err{category: code2.CatResource, code: code2.InsufficientPermission}, want: http.StatusUnauthorized},
|
||||||
{name: "resource insufficient", err: &Err{category: code.CatResource, code: code.ResourceInsufficient}, want: http.StatusBadRequest},
|
{name: "resource insufficient", err: &Err{category: code2.CatResource, code: code2.ResourceInsufficient}, want: http.StatusBadRequest},
|
||||||
{name: "invalid format", err: &Err{category: code.CatInput, code: code.InvalidFormat}, want: http.StatusBadRequest},
|
{name: "invalid format", err: &Err{category: code2.CatInput, code: code2.InvalidFormat}, want: http.StatusBadRequest},
|
||||||
{name: "resource not found", err: &Err{code: code.ResourceNotFound}, want: http.StatusNotFound},
|
{name: "resource not found", err: &Err{code: code2.ResourceNotFound}, want: http.StatusNotFound},
|
||||||
{name: "ok", err: &Err{code: code.OK}, want: http.StatusOK},
|
{name: "ok", err: &Err{code: code2.OK}, want: http.StatusOK},
|
||||||
{name: "not valid implementation", err: &Err{category: code.CatInput, code: code.NotValidImplementation}, want: http.StatusNotImplemented},
|
{name: "not valid implementation", err: &Err{category: code2.CatInput, code: code2.NotValidImplementation}, want: http.StatusNotImplemented},
|
||||||
{name: "forbidden", err: &Err{category: code.CatAuth, code: code.Forbidden}, want: http.StatusForbidden},
|
{name: "forbidden", err: &Err{category: code2.CatAuth, code: code2.Forbidden}, want: http.StatusForbidden},
|
||||||
{name: "insufficient quota", err: &Err{category: code.CatResource, code: code.InsufficientQuota}, want: http.StatusPaymentRequired},
|
{name: "insufficient quota", err: &Err{category: code2.CatResource, code: code2.InsufficientQuota}, want: http.StatusPaymentRequired},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
|
@ -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
|
||||||
|
```
|
Loading…
Reference in New Issue