Compare commits

..

8 Commits

Author SHA1 Message Date
332803d8de update workflows
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-10-27 22:52:48 +03:00
11c868d476 Merge branch 'v3' 2021-10-27 22:51:58 +03:00
38d6e482d7 util/reflect: fix StructFields
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-10-27 22:51:35 +03:00
07d4085201 util/reflect: fix reflect methods
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-10-27 12:55:48 +03:00
45f30c0be3 util/reflect: ZeroFieldByPath and SetFieldByPath
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-10-26 14:12:37 +03:00
bcaea675a7 util/reflect: add method to zero struct field
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-10-25 14:41:19 +03:00
3087ba1d73 regen
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-10-23 23:45:53 +03:00
6af837fd25 fixup workflows
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-10-02 18:42:20 +03:00
17 changed files with 274 additions and 134 deletions

View File

@@ -3,6 +3,7 @@ on:
push:
branches:
- master
- v3
jobs:
test:
name: test

View File

@@ -9,7 +9,7 @@
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
name: "codeql"
on:
workflow_run:
@@ -17,16 +17,16 @@ on:
types:
- completed
push:
branches: [ master ]
branches: [ master, v3 ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
branches: [ master, v3 ]
schedule:
- cron: '34 1 * * 0'
jobs:
analyze:
name: Analyze
name: analyze
runs-on: ubuntu-latest
permissions:
actions: read
@@ -42,11 +42,14 @@ jobs:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
- name: checkout
uses: actions/checkout@v2
- name: setup
uses: actions/setup-go@v2
with:
go-version: 1.16
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- name: init
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
@@ -57,7 +60,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
- name: autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
@@ -71,5 +74,5 @@ jobs:
# make bootstrap
# make release
- name: Perform CodeQL Analysis
- name: analyze
uses: github/codeql-action/analyze@v1

View File

@@ -1,66 +1,31 @@
name: "prautomerge"
on:
workflow_run:
workflows: ["prbuild"]
types:
- completed
pull_request_target:
types: [assigned, opened, synchronize, reopened]
permissions:
contents: write
pull-requests: write
contents: write
jobs:
Dependabot-Automerge:
dependabot:
runs-on: ubuntu-latest
# Contains workaround to execute if dependabot updates the PR by checking for the base branch in the linked PR
# The the github.event.workflow_run.event value is 'push' and not 'pull_request'
# dont work with multiple workflows when last returns success
if: >-
github.event.workflow_run.conclusion == 'success'
&& github.actor == 'dependabot[bot]'
&& github.event.sender.login == 'dependabot[bot]'
&& github.event.sender.type == 'Bot'
&& (github.event.workflow_run.event == 'pull_request'
|| (github.event.workflow_run.event == 'push' && github.event.workflow_run.pull_requests[0].base.ref == github.event.repository.default_branch ))
if: ${{ github.actor == 'dependabot[bot]' }}
steps:
- name: Approve Changes and Merge changes if label 'dependencies' is set
uses: actions/github-script@v5
- name: metadata
id: metadata
uses: dependabot/fetch-metadata@v1.1.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
console.log(context.payload.workflow_run);
var labelNames = await github.paginate(
github.issues.listLabelsOnIssue,
{
repo: context.repo.repo,
owner: context.repo.owner,
issue_number: context.payload.workflow_run.pull_requests[0].number,
},
(response) => response.data.map(
(label) => label.name
)
);
console.log(labelNames);
if (labelNames.includes('dependencies')) {
console.log('Found label');
await github.pulls.createReview({
repo: context.repo.repo,
owner: context.repo.owner,
pull_number: context.payload.workflow_run.pull_requests[0].number,
event: 'APPROVE'
});
console.log('Approved PR');
await github.pulls.merge({
repo: context.repo.repo,
owner: context.repo.owner,
pull_number: context.payload.workflow_run.pull_requests[0].number,
});
console.log('Merged PR');
}
github-token: "${{ secrets.TOKEN }}"
- name: approve
run: gh pr review --approve "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.TOKEN}}
- name: merge
if: ${{contains(steps.metadata.outputs.dependency-names, 'go.unistack.org')}}
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.TOKEN}}

View File

@@ -3,6 +3,7 @@ on:
pull_request:
branches:
- master
- v3
jobs:
test:
name: test

View File

@@ -17,7 +17,7 @@ syntax = "proto3";
package micro.codec;
option cc_enable_arenas = true;
option go_package = "github.com/unistack-org/micro/v3/codec;codec";
option go_package = "go.unistack.org/micro/v3/codec;codec";
option java_multiple_files = true;
option java_outer_classname = "MicroCodec";
option java_package = "micro.codec";

2
go.mod
View File

@@ -8,7 +8,7 @@ require (
github.com/imdario/mergo v0.3.12
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/silas/dag v0.0.0-20210626123444-3804bac2d6d4
github.com/unistack-org/micro-proto v0.0.9
go.unistack.org/micro-proto/v3 v3.1.0
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
)

10
go.sum
View File

@@ -1,7 +1,5 @@
github.com/ef-ds/deque v1.0.4 h1:iFAZNmveMT9WERAkqLJ+oaABF9AcVQ5AjXem/hroniI=
github.com/ef-ds/deque v1.0.4/go.mod h1:gXDnTC3yqvBcHbq2lcExjtAcVrOnJCbMcZXmuj8Z4tg=
github.com/golang-jwt/jwt/v4 v4.0.0 h1:RAqyYixv1p7uEnocuy8P1nru5wprCh/MH2BIlW5z5/o=
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0=
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
@@ -11,14 +9,10 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/silas/dag v0.0.0-20210121180416-41cf55125c34 h1:vBfVmA5mZhsQa2jr1FOL9nfA37N/jnbBmi5XUfviVTI=
github.com/silas/dag v0.0.0-20210121180416-41cf55125c34/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
github.com/silas/dag v0.0.0-20210626123444-3804bac2d6d4 h1:fOH64AB0C3ixGf9emky61STvPJL3smxJg+1Zwx1oCdg=
github.com/silas/dag v0.0.0-20210626123444-3804bac2d6d4/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
github.com/unistack-org/micro-proto v0.0.9 h1:KrWLS4FUX7UAWNAilQf70uad6ZPf/0EudeddCXllRVc=
github.com/unistack-org/micro-proto v0.0.9/go.mod h1:Cckwmzd89gvS7ThxzZp9kQR/EOdksFQcsTAtDDyKwrg=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
go.unistack.org/micro-proto/v3 v3.1.0 h1:q39FwjFiRZn+Ux/tt+d3bJTmDtsQQWa+3SLYVo1vLfA=
go.unistack.org/micro-proto/v3 v3.1.0/go.mod h1:DpRhYCBXlmSJ/AAXTmntvlh7kQkYU6eFvlmYAx4BQS8=
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b h1:eB48h3HiRycXNy8E0Gf5e0hv7YT6Kt14L/D73G1fuwo=
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View File

@@ -1,12 +1,12 @@
package meter
//go:generate sh -c "protoc -I./handler -I../ -I$(go list -f '{{ .Dir }}' -m github.com/unistack-org/micro-proto) --go-micro_out='components=micro|http|server',standalone=false,debug=true,paths=source_relative:./handler handler/handler.proto"
//go:generate sh -c "protoc -I./handler -I../ -I$(go list -f '{{ .Dir }}' -m go.unistack.org/micro-proto/v3) --go-micro_out='components=micro|http|server',standalone=false,debug=true,paths=source_relative:./handler handler/handler.proto"
import (
// import required packages
_ "github.com/unistack-org/micro-proto/api"
_ "go.unistack.org/micro-proto/v3/api"
// import required packages
_ "github.com/unistack-org/micro-proto/openapiv2"
_ "go.unistack.org/micro-proto/v3/openapiv3"
)

View File

@@ -1,24 +1,20 @@
syntax = "proto3";
package micro.meter.handler;
option go_package = "github.com/unistack-org/micro/v3/meter/handler;handler";
option go_package = "go.unistack.org/micro/v3/meter/handler;handler";
import "api/annotations.proto";
import "openapiv2/annotations.proto";
import "openapiv3/annotations.proto";
import "codec/frame.proto";
service Meter {
rpc Metrics(micro.codec.Frame) returns (micro.codec.Frame) {
option (micro.openapiv2.openapiv2_operation) = {
option (micro.openapiv3.openapiv3_operation) = {
operation_id: "Metrics";
responses: {
response_code: {
name: "default";
value: {
json_reference: {
description: "Error response";
_ref: "micro.codec.Frame";
};
default: {
reference: {
_ref: "micro.codec.Frame";
};
};
};

View File

@@ -1,12 +1,11 @@
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
// protoc-gen-go-micro version: v3.4.2
// protoc-gen-go-micro version: v3.5.2
// source: handler.proto
package handler
import (
context "context"
api "go.unistack.org/micro/v3/api"
codec "go.unistack.org/micro/v3/codec"
)

View File

@@ -1,12 +1,11 @@
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
// protoc-gen-go-micro version: v3.4.2
// protoc-gen-go-micro version: v3.5.2
// source: handler.proto
package handler
import (
context "context"
api "go.unistack.org/micro/v3/api"
codec "go.unistack.org/micro/v3/codec"
server "go.unistack.org/micro/v3/server"

View File

@@ -1,12 +1,12 @@
package server
//go:generate sh -c "protoc -I./health -I../ -I$(go list -f '{{ .Dir }}' -m github.com/unistack-org/micro-proto) --go-micro_out='components=micro|http|server',standalone=false,debug=true,paths=source_relative:./health health/health.proto"
//go:generate sh -c "protoc -I./health -I../ -I$(go list -f '{{ .Dir }}' -m go.unistack.org/micro-proto/v3) --go-micro_out='components=micro|http|server',standalone=false,debug=true,paths=source_relative:./health health/health.proto"
import (
// import required packages
_ "github.com/unistack-org/micro-proto/api"
_ "go.unistack.org/micro-proto/v3/api"
// import required packages
_ "github.com/unistack-org/micro-proto/openapiv2"
_ "go.unistack.org/micro-proto/v3/openapiv3"
)

View File

@@ -1,24 +1,20 @@
syntax = "proto3";
package micro.server.health;
option go_package = "github.com/unistack-org/micro/v3/server/health;health";
option go_package = "go.unistack.org/micro/v3/server/health;health";
import "api/annotations.proto";
import "openapiv2/annotations.proto";
import "openapiv3/annotations.proto";
import "codec/frame.proto";
service Health {
rpc Live(micro.codec.Frame) returns (micro.codec.Frame) {
option (micro.openapiv2.openapiv2_operation) = {
option (micro.openapiv3.openapiv3_operation) = {
operation_id: "Live";
responses: {
response_code: {
name: "default";
value: {
json_reference: {
description: "Error response";
_ref: "micro.codec.Frame";
};
default: {
reference: {
_ref: "micro.codec.Frame";
};
};
};
@@ -26,16 +22,12 @@ service Health {
option (micro.api.http) = { get: "/live"; };
};
rpc Ready(micro.codec.Frame) returns (micro.codec.Frame) {
option (micro.openapiv2.openapiv2_operation) = {
option (micro.openapiv3.openapiv3_operation) = {
operation_id: "Ready";
responses: {
response_code: {
name: "default";
value: {
json_reference: {
description: "Error response";
_ref: "micro.codec.Frame";
};
default: {
reference: {
_ref: "micro.codec.Frame";
};
};
};
@@ -43,16 +35,12 @@ service Health {
option (micro.api.http) = { get: "/ready"; };
};
rpc Version(micro.codec.Frame) returns (micro.codec.Frame) {
option (micro.openapiv2.openapiv2_operation) = {
option (micro.openapiv3.openapiv3_operation) = {
operation_id: "Version";
responses: {
response_code: {
name: "default";
value: {
json_reference: {
description: "Error response";
_ref: "micro.codec.Frame";
};
default: {
reference: {
_ref: "micro.codec.Frame";
};
};
};

View File

@@ -1,12 +1,11 @@
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
// protoc-gen-go-micro version: v3.4.2
// protoc-gen-go-micro version: v3.5.2
// source: health.proto
package health
import (
context "context"
api "go.unistack.org/micro/v3/api"
codec "go.unistack.org/micro/v3/codec"
)

View File

@@ -1,12 +1,11 @@
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
// protoc-gen-go-micro version: v3.4.2
// protoc-gen-go-micro version: v3.5.2
// source: health.proto
package health
import (
context "context"
api "go.unistack.org/micro/v3/api"
codec "go.unistack.org/micro/v3/codec"
server "go.unistack.org/micro/v3/server"

View File

@@ -7,6 +7,7 @@ import (
"reflect"
"regexp"
"strings"
"time"
)
// ErrInvalidParam specifies invalid url query params
@@ -69,6 +70,89 @@ func StructFieldByTag(src interface{}, tkey string, tval string) (interface{}, e
return nil, ErrNotFound
}
// ZeroFieldByPath clean struct field by its path
func ZeroFieldByPath(src interface{}, path string) error {
var err error
val := reflect.ValueOf(src)
for _, p := range strings.Split(path, ".") {
val, err = structValueByName(val, p)
if err != nil {
return err
}
}
if IsEmpty(val) {
return nil
}
if !val.CanSet() {
return ErrInvalidStruct
}
val.Set(reflect.Zero(val.Type()))
return nil
}
// SetFieldByPath set struct field by its path
func SetFieldByPath(src interface{}, dst interface{}, path string) error {
var err error
val := reflect.ValueOf(src)
for _, p := range strings.Split(path, ".") {
val, err = structValueByName(val, p)
if err != nil {
return err
}
}
if !val.CanSet() {
return ErrInvalidStruct
}
val.Set(reflect.ValueOf(dst))
return nil
}
// structValueByName get struct field by its name
func structValueByName(sv reflect.Value, tkey string) (reflect.Value, error) {
if sv.Kind() == reflect.Ptr {
sv = sv.Elem()
}
if sv.Kind() != reflect.Struct {
return reflect.Zero(reflect.TypeOf(sv)), ErrInvalidStruct
}
typ := sv.Type()
for idx := 0; idx < typ.NumField(); idx++ {
fld := typ.Field(idx)
val := sv.Field(idx)
if len(fld.PkgPath) != 0 {
continue
}
if fld.Name == tkey || strings.EqualFold(strings.ToLower(fld.Name), strings.ToLower(tkey)) {
return val, nil
}
switch val.Kind() {
case reflect.Ptr:
if val = val.Elem(); val.Kind() == reflect.Struct {
if iface, err := structValueByName(val, tkey); err == nil {
return iface, nil
}
}
case reflect.Struct:
if iface, err := structValueByName(val, tkey); err == nil {
return iface, nil
}
}
}
return reflect.Zero(reflect.TypeOf(sv)), ErrNotFound
}
// StructFieldByPath get struct field by its path
func StructFieldByPath(src interface{}, path string) (interface{}, error) {
var err error
@@ -98,10 +182,7 @@ func StructFieldByName(src interface{}, tkey string) (interface{}, error) {
if len(fld.PkgPath) != 0 {
continue
}
if fld.Name == tkey {
if val.Kind() != reflect.Ptr && val.CanAddr() {
val = val.Addr()
}
if fld.Name == tkey || strings.EqualFold(strings.ToLower(fld.Name), strings.ToLower(tkey)) {
return val.Interface(), nil
}
@@ -153,10 +234,30 @@ func StructFields(src interface{}) ([]StructField, error) {
continue
}
switch val.Interface().(type) {
case time.Time, *time.Time:
fields = append(fields, StructField{Field: fld, Value: val, Path: fld.Name})
continue
case time.Duration, *time.Duration:
fields = append(fields, StructField{Field: fld, Value: val, Path: fld.Name})
continue
}
switch val.Kind() {
// case timeKind:
// fmt.Printf("GGG\n")
// fields = append(fields, StructField{Field: fld, Value: val, Path: fld.Name})
case reflect.Ptr:
// if !val.IsValid()
if reflect.Indirect(val).Kind() == reflect.Struct {
infields, err := StructFields(val.Interface())
if err != nil {
return nil, err
}
for _, infield := range infields {
infield.Path = fmt.Sprintf("%s.%s", fld.Name, infield.Path)
fields = append(fields, infield)
}
} else {
fields = append(fields, StructField{Field: fld, Value: val, Path: fld.Name})
}
case reflect.Struct:
infields, err := StructFields(val.Interface())
if err != nil {

View File

@@ -4,10 +4,105 @@ import (
"net/url"
"reflect"
"testing"
"time"
rutil "go.unistack.org/micro/v3/util/reflect"
)
func TestStructfields(t *testing.T) {
type Config struct {
Wait time.Duration
Time time.Time
Metadata map[string]int
Broker string
Addr []string
Verbose bool
Nested *Config
}
cfg := &Config{Nested: &Config{}}
fields, err := rutil.StructFields(cfg)
if err != nil {
t.Fatal(err)
}
if len(fields) != 13 {
t.Fatalf("invalid fields number: %v", fields)
}
}
func TestSetFieldByPath(t *testing.T) {
type NestedStr struct {
BBB string `json:"bbb"`
CCC int `json:"ccc"`
}
type Str1 struct {
Name []string `json:"name" codec:"flatten"`
XXX string `json:"xxx"`
Nested NestedStr `json:"nested"`
}
type Str2 struct {
XXX string `json:"xxx"`
Nested *NestedStr `json:"nested"`
Name []string `json:"name" codec:"flatten"`
}
var err error
val1 := &Str1{Name: []string{"first", "second"}, XXX: "ttt", Nested: NestedStr{BBB: "ddd", CCC: 9}}
val2 := &Str2{Name: []string{"first", "second"}, XXX: "ttt", Nested: &NestedStr{BBB: "ddd", CCC: 9}}
err = rutil.SetFieldByPath(val1, "xxx", "Nested.BBB")
if err != nil {
t.Fatal(err)
}
if val1.Nested.BBB != "xxx" {
t.Fatalf("SetFieldByPath not works: %#+v", val1)
}
err = rutil.SetFieldByPath(val2, "xxx", "Nested.BBB")
if err != nil {
t.Fatal(err)
}
if val2.Nested.BBB != "xxx" {
t.Fatalf("SetFieldByPath not works: %#+v", val1)
}
}
func TestZeroFieldByPath(t *testing.T) {
type NestedStr struct {
BBB string `json:"bbb"`
CCC int `json:"ccc"`
}
type Str1 struct {
Name []string `json:"name" codec:"flatten"`
XXX string `json:"xxx"`
Nested NestedStr `json:"nested"`
}
type Str2 struct {
XXX string `json:"xxx"`
Nested *NestedStr `json:"nested"`
Name []string `json:"name" codec:"flatten"`
}
var err error
val1 := &Str1{Name: []string{"first", "second"}, XXX: "ttt", Nested: NestedStr{BBB: "ddd", CCC: 9}}
err = rutil.ZeroFieldByPath(val1, "Nested.BBB")
if err != nil {
t.Fatal(err)
}
err = rutil.ZeroFieldByPath(val1, "Nested")
if err != nil {
t.Fatal(err)
}
if val1.Nested.BBB == "ddd" {
t.Fatalf("zero field not works: %v", val1)
}
val2 := &Str2{Name: []string{"first", "second"}, XXX: "ttt", Nested: &NestedStr{BBB: "ddd", CCC: 9}}
err = rutil.ZeroFieldByPath(val2, "Nested")
if err != nil {
t.Fatal(err)
}
if val2.Nested != nil {
t.Fatalf("zero field not works: %v", val2)
}
}
func TestStructFieldsMap(t *testing.T) {
type NestedStr struct {
BBB string
@@ -108,9 +203,9 @@ func TestStructByName(t *testing.T) {
t.Fatal(err)
}
if v, ok := iface.(*[]string); !ok {
t.Fatalf("not *[]string %v", iface)
} else if len(*v) != 2 {
if v, ok := iface.([]string); !ok {
t.Fatalf("not []string %v", iface)
} else if len(v) != 2 {
t.Fatalf("invalid number %v", iface)
}
}