support message reference #42

Merged
vtolstov merged 2 commits from messageref into v3 2022-03-19 15:17:56 +03:00
11 changed files with 154 additions and 105 deletions

20
.github/workflows/autoapprove.yml vendored Normal file
View File

@ -0,0 +1,20 @@
name: "autoapprove"
on:
pull_request_target:
types: [assigned, opened, synchronize, reopened]
permissions:
pull-requests: write
contents: write
jobs:
autoapprove:
runs-on: ubuntu-latest
steps:
- name: approve
uses: hmarr/auto-approve-action@v2
if: github.actor == 'vtolstov' || github.actor == 'dependabot[bot]'
id: approve
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

21
.github/workflows/automerge.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: "automerge"
on:
pull_request_target:
types: [assigned, opened, synchronize, reopened]
permissions:
pull-requests: write
contents: write
jobs:
automerge:
runs-on: ubuntu-latest
if: github.actor == 'vtolstov'
steps:
- name: merge
id: merge
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:
push: push:
branches: branches:
- master - master
- v3
jobs: jobs:
test: test:
name: test name: test
@ -33,7 +34,7 @@ jobs:
- name: checkout - name: checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: lint - name: lint
uses: golangci/golangci-lint-action@v3 uses: golangci/golangci-lint-action@v3.1.0
continue-on-error: true continue-on-error: true
with: with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.

View File

@ -9,7 +9,7 @@
# the `language` matrix defined below to confirm you have the correct set of # the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages. # supported CodeQL languages.
# #
name: "CodeQL" name: "codeql"
on: on:
workflow_run: workflow_run:
@ -17,16 +17,16 @@ on:
types: types:
- completed - completed
push: push:
branches: [ master ] branches: [ master, v3 ]
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [ master ] branches: [ master, v3 ]
schedule: schedule:
- cron: '34 1 * * 0' - cron: '34 1 * * 0'
jobs: jobs:
analyze: analyze:
name: Analyze name: analyze
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
actions: read 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 # 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: steps:
- name: Checkout repository - name: checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: setup
uses: actions/setup-go@v2
with:
go-version: 1.17
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: init
uses: github/codeql-action/init@v1 uses: github/codeql-action/init@v1
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
@ -57,7 +60,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # 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) # 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 uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell. # Command-line programs to run using the OS shell.
@ -71,5 +74,5 @@ jobs:
# make bootstrap # make bootstrap
# make release # make release
- name: Perform CodeQL Analysis - name: analyze
uses: github/codeql-action/analyze@v1 uses: github/codeql-action/analyze@v1

View File

@ -1,66 +1,27 @@
name: "prautomerge" name: "dependabot-automerge"
on: on:
workflow_run: pull_request_target:
workflows: ["prbuild"] types: [assigned, opened, synchronize, reopened]
types:
- completed
permissions: permissions:
contents: write
pull-requests: write pull-requests: write
contents: write
jobs: jobs:
Dependabot-Automerge: automerge:
runs-on: ubuntu-latest runs-on: ubuntu-latest
# Contains workaround to execute if dependabot updates the PR by checking for the base branch in the linked PR if: github.actor == 'dependabot[bot]'
# 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 ))
steps: steps:
- name: Approve Changes and Merge changes if label 'dependencies' is set - name: metadata
uses: actions/github-script@v6 id: metadata
uses: dependabot/fetch-metadata@v1.3.0
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: "${{ secrets.TOKEN }}"
script: | - name: merge
console.log(context.payload.workflow_run); id: merge
if: ${{contains(steps.metadata.outputs.dependency-names, 'go.unistack.org')}}
var labelNames = await github.paginate( run: gh pr merge --auto --merge "$PR_URL"
github.issues.listLabelsOnIssue, env:
{ PR_URL: ${{github.event.pull_request.html_url}}
repo: context.repo.repo, GITHUB_TOKEN: ${{secrets.TOKEN}}
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');
}

View File

@ -3,6 +3,7 @@ on:
pull_request: pull_request:
branches: branches:
- master - master
- v3
jobs: jobs:
test: test:
name: test name: test
@ -33,7 +34,7 @@ jobs:
- name: checkout - name: checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: lint - name: lint
uses: golangci/golangci-lint-action@v3 uses: golangci/golangci-lint-action@v3.1.0
continue-on-error: true continue-on-error: true
with: with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.

View File

@ -40,13 +40,13 @@ func (g *Generator) httpGenerate(component string, plugin *protogen.Plugin, genC
for _, service := range file.Services { for _, service := range file.Services {
if genClient { if genClient {
generateServiceClient(gfile, service) g.generateServiceClient(gfile, service)
generateServiceClientMethods(gfile, service, true) g.generateServiceClientMethods(gfile, service, true)
} }
if genServer { if genServer {
generateServiceServer(gfile, service) generateServiceServer(gfile, service)
generateServiceServerMethods(gfile, service) g.generateServiceServerMethods(gfile, service)
generateServiceRegister(gfile, service) g.generateServiceRegister(gfile, service)
} }
} }
} }

View File

@ -45,11 +45,13 @@ type Generator struct {
fieldaligment bool fieldaligment bool
tagPath string tagPath string
openapiFile string openapiFile string
plugin *protogen.Plugin
} }
func (g *Generator) Generate(plugin *protogen.Plugin) error { func (g *Generator) Generate(plugin *protogen.Plugin) error {
var err error var err error
g.plugin = plugin
g.standalone = *flagStandalone g.standalone = *flagStandalone
g.debug = *flagDebug g.debug = *flagDebug
g.components = *flagComponents g.components = *flagComponents

View File

@ -35,14 +35,14 @@ func (g *Generator) microGenerate(component string, plugin *protogen.Plugin, gen
} }
// generate services // generate services
for _, service := range file.Services { for _, service := range file.Services {
generateServiceEndpoints(gfile, service) g.generateServiceEndpoints(gfile, service)
if genClient { if genClient {
generateServiceClientInterface(gfile, service) g.generateServiceClientInterface(gfile, service)
generateServiceClientStreamInterface(gfile, service) g.generateServiceClientStreamInterface(gfile, service)
} }
if genServer { if genServer {
generateServiceServerInterface(gfile, service) g.generateServiceServerInterface(gfile, service)
generateServiceServerStreamInterface(gfile, service) g.generateServiceServerStreamInterface(gfile, service)
} }
} }

8
rpc.go
View File

@ -37,13 +37,13 @@ func (g *Generator) rpcGenerate(component string, plugin *protogen.Plugin, genCl
} }
for _, service := range file.Services { for _, service := range file.Services {
if genClient { if genClient {
generateServiceClient(gfile, service) g.generateServiceClient(gfile, service)
generateServiceClientMethods(gfile, service, false) g.generateServiceClientMethods(gfile, service, false)
} }
if genServer { if genServer {
generateServiceServer(gfile, service) generateServiceServer(gfile, service)
generateServiceServerMethods(gfile, service) g.generateServiceServerMethods(gfile, service)
generateServiceRegister(gfile, service) g.generateServiceRegister(gfile, service)
} }
} }
} }

90
util.go
View File

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"log"
"net/http" "net/http"
"strings" "strings"
@ -28,7 +29,7 @@ func unexport(s string) string {
return strings.ToLower(s[:1]) + s[1:] return strings.ToLower(s[:1]) + s[1:]
} }
func generateServiceClient(gfile *protogen.GeneratedFile, service *protogen.Service) { func (g *Generator) generateServiceClient(gfile *protogen.GeneratedFile, service *protogen.Service) {
serviceName := service.GoName serviceName := service.GoName
// if rule, ok := getMicroApiService(service); ok { // if rule, ok := getMicroApiService(service); ok {
// gfile.P("// client wrappers ", strings.Join(rule.ClientWrappers, ", ")) // gfile.P("// client wrappers ", strings.Join(rule.ClientWrappers, ", "))
@ -44,11 +45,11 @@ func generateServiceClient(gfile *protogen.GeneratedFile, service *protogen.Serv
gfile.P() gfile.P()
} }
func generateServiceClientMethods(gfile *protogen.GeneratedFile, service *protogen.Service, http bool) { func (g *Generator) generateServiceClientMethods(gfile *protogen.GeneratedFile, service *protogen.Service, http bool) {
serviceName := service.GoName serviceName := service.GoName
for _, method := range service.Methods { for _, method := range service.Methods {
methodName := fmt.Sprintf("%s.%s", serviceName, method.GoName) methodName := fmt.Sprintf("%s.%s", serviceName, method.GoName)
generateClientFuncSignature(gfile, serviceName, method) g.generateClientFuncSignature(gfile, serviceName, method)
if http && method.Desc.Options() != nil { if http && method.Desc.Options() != nil {
if proto.HasExtension(method.Desc.Options(), v2.E_Openapiv2Operation) { if proto.HasExtension(method.Desc.Options(), v2.E_Openapiv2Operation) {
@ -61,20 +62,25 @@ func generateServiceClientMethods(gfile *protogen.GeneratedFile, service *protog
gfile.P("errmap := make(map[string]interface{}, ", len(r.Responses.ResponseCode), ")") gfile.P("errmap := make(map[string]interface{}, ", len(r.Responses.ResponseCode), ")")
for _, rsp := range r.Responses.ResponseCode { for _, rsp := range r.Responses.ResponseCode {
if schema := rsp.Value.GetJsonReference(); schema != nil { if schema := rsp.Value.GetJsonReference(); schema != nil {
ref := schema.XRef xref := schema.XRef
if strings.HasPrefix(ref, "."+string(service.Desc.ParentFile().Package())+".") { if strings.HasPrefix(xref, "."+string(service.Desc.ParentFile().Package())+".") {
ref = strings.TrimPrefix(ref, "."+string(service.Desc.ParentFile().Package())+".") xref = strings.TrimPrefix(xref, "."+string(service.Desc.ParentFile().Package())+".")
} }
if ref[0] == '.' { if xref[0] == '.' {
ref = ref[1:] xref = xref[1:]
} }
switch ref { switch xref {
case "micro.codec.Frame": case "micro.codec.Frame":
gfile.P(`errmap["`, rsp.Name, `"] = &`, microCodecPackage.Ident("Frame"), "{}") gfile.P(`errmap["`, rsp.Name, `"] = &`, microCodecPackage.Ident("Frame"), "{}")
case "micro.errors.Error": case "micro.errors.Error":
gfile.P(`errmap["`, rsp.Name, `"] = &`, microErrorsPackage.Ident("Error"), "{}") gfile.P(`errmap["`, rsp.Name, `"] = &`, microErrorsPackage.Ident("Error"), "{}")
default: default:
gfile.P(`errmap["`, rsp.Name, `"] = &`, ref, "{}") ident, err := g.getGoIdentByXref(strings.TrimPrefix(schema.XRef, "."))
if err != nil {
log.Printf("cant find message by ref %s\n", schema.XRef)
continue
}
gfile.P(`errmap["`, rsp.Name, `"] = &`, gfile.QualifiedGoIdent(ident), "{}")
} }
} }
} }
@ -97,20 +103,25 @@ func generateServiceClientMethods(gfile *protogen.GeneratedFile, service *protog
gfile.P("errmap := make(map[string]interface{}, ", len(resps), ")") gfile.P("errmap := make(map[string]interface{}, ", len(resps), ")")
for _, rsp := range resps { for _, rsp := range resps {
if schema := rsp.Value.GetReference(); schema != nil { if schema := rsp.Value.GetReference(); schema != nil {
ref := schema.XRef xref := schema.XRef
if strings.HasPrefix(ref, "."+string(service.Desc.ParentFile().Package())+".") { if strings.HasPrefix(xref, "."+string(service.Desc.ParentFile().Package())+".") {
ref = strings.TrimPrefix(ref, "."+string(service.Desc.ParentFile().Package())+".") xref = strings.TrimPrefix(xref, "."+string(service.Desc.ParentFile().Package())+".")
} }
if ref[0] == '.' { if xref[0] == '.' {
ref = ref[1:] xref = xref[1:]
} }
switch ref { switch xref {
case "micro.codec.Frame": case "micro.codec.Frame":
gfile.P(`errmap["`, rsp.Name, `"] = &`, microCodecPackage.Ident("Frame"), "{}") gfile.P(`errmap["`, rsp.Name, `"] = &`, microCodecPackage.Ident("Frame"), "{}")
case "micro.errors.Error": case "micro.errors.Error":
gfile.P(`errmap["`, rsp.Name, `"] = &`, microErrorsPackage.Ident("Error"), "{}") gfile.P(`errmap["`, rsp.Name, `"] = &`, microErrorsPackage.Ident("Error"), "{}")
default: default:
gfile.P(`errmap["`, rsp.Name, `"] = &`, ref, "{}") ident, err := g.getGoIdentByXref(strings.TrimPrefix(schema.XRef, "."))
if err != nil {
log.Printf("cant find message by ref %s\n", schema.XRef)
continue
}
gfile.P(`errmap["`, rsp.Name, `"] = &`, gfile.QualifiedGoIdent(ident), "{}")
} }
} }
} }
@ -300,7 +311,7 @@ func generateServiceServer(gfile *protogen.GeneratedFile, service *protogen.Serv
gfile.P() gfile.P()
} }
func generateServiceServerMethods(gfile *protogen.GeneratedFile, service *protogen.Service) { func (g *Generator) generateServiceServerMethods(gfile *protogen.GeneratedFile, service *protogen.Service) {
serviceName := service.GoName serviceName := service.GoName
for _, method := range service.Methods { for _, method := range service.Methods {
generateServerFuncSignature(gfile, serviceName, method, true) generateServerFuncSignature(gfile, serviceName, method, true)
@ -444,7 +455,7 @@ func generateServiceServerMethods(gfile *protogen.GeneratedFile, service *protog
} }
} }
func generateServiceRegister(gfile *protogen.GeneratedFile, service *protogen.Service) { func (g *Generator) generateServiceRegister(gfile *protogen.GeneratedFile, service *protogen.Service) {
serviceName := service.GoName serviceName := service.GoName
gfile.P("func Register", serviceName, "Server(s ", microServerPackage.Ident("Server"), ", sh ", serviceName, "Server, opts ...", microServerPackage.Ident("HandlerOption"), ") error {") gfile.P("func Register", serviceName, "Server(s ", microServerPackage.Ident("Server"), ", sh ", serviceName, "Server, opts ...", microServerPackage.Ident("HandlerOption"), ") error {")
gfile.P("type ", unexport(serviceName), " interface {") gfile.P("type ", unexport(serviceName), " interface {")
@ -508,7 +519,7 @@ func generateServerSignature(gfile *protogen.GeneratedFile, serviceName string,
gfile.P(args...) gfile.P(args...)
} }
func generateClientFuncSignature(gfile *protogen.GeneratedFile, serviceName string, method *protogen.Method) { func (g *Generator) generateClientFuncSignature(gfile *protogen.GeneratedFile, serviceName string, method *protogen.Method) {
args := append([]interface{}{}, args := append([]interface{}{},
"func (c *", "func (c *",
unexport(serviceName), unexport(serviceName),
@ -547,7 +558,7 @@ func generateClientSignature(gfile *protogen.GeneratedFile, serviceName string,
gfile.P(args...) gfile.P(args...)
} }
func generateServiceClientInterface(gfile *protogen.GeneratedFile, service *protogen.Service) { func (g *Generator) generateServiceClientInterface(gfile *protogen.GeneratedFile, service *protogen.Service) {
serviceName := service.GoName serviceName := service.GoName
gfile.P("type ", serviceName, "Client interface {") gfile.P("type ", serviceName, "Client interface {")
for _, method := range service.Methods { for _, method := range service.Methods {
@ -557,7 +568,7 @@ func generateServiceClientInterface(gfile *protogen.GeneratedFile, service *prot
gfile.P() gfile.P()
} }
func generateServiceServerInterface(gfile *protogen.GeneratedFile, service *protogen.Service) { func (g *Generator) generateServiceServerInterface(gfile *protogen.GeneratedFile, service *protogen.Service) {
serviceName := service.GoName serviceName := service.GoName
gfile.P("type ", serviceName, "Server interface {") gfile.P("type ", serviceName, "Server interface {")
for _, method := range service.Methods { for _, method := range service.Methods {
@ -567,7 +578,7 @@ func generateServiceServerInterface(gfile *protogen.GeneratedFile, service *prot
gfile.P() gfile.P()
} }
func generateServiceClientStreamInterface(gfile *protogen.GeneratedFile, service *protogen.Service) { func (g *Generator) generateServiceClientStreamInterface(gfile *protogen.GeneratedFile, service *protogen.Service) {
serviceName := service.GoName serviceName := service.GoName
for _, method := range service.Methods { for _, method := range service.Methods {
if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() {
@ -594,7 +605,7 @@ func generateServiceClientStreamInterface(gfile *protogen.GeneratedFile, service
} }
} }
func generateServiceServerStreamInterface(gfile *protogen.GeneratedFile, service *protogen.Service) { func (g *Generator) generateServiceServerStreamInterface(gfile *protogen.GeneratedFile, service *protogen.Service) {
serviceName := service.GoName serviceName := service.GoName
for _, method := range service.Methods { for _, method := range service.Methods {
if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() {
@ -621,7 +632,7 @@ func generateServiceServerStreamInterface(gfile *protogen.GeneratedFile, service
} }
} }
func generateServiceEndpoints(gfile *protogen.GeneratedFile, service *protogen.Service) { func (g *Generator) generateServiceEndpoints(gfile *protogen.GeneratedFile, service *protogen.Service) {
serviceName := service.GoName serviceName := service.GoName
gfile.P("var (") gfile.P("var (")
gfile.P(serviceName, "Name", "=", `"`, serviceName, `"`) gfile.P(serviceName, "Name", "=", `"`, serviceName, `"`)
@ -755,3 +766,32 @@ func generateEndpoint(gfile *protogen.GeneratedFile, serviceName string, methodN
} }
gfile.P(`Handler: "rpc",`) gfile.P(`Handler: "rpc",`)
} }
func (g *Generator) getGoIdentByXref(xref string) (protogen.GoIdent, error) {
idx := strings.LastIndex(xref, ".")
pkg := xref[:idx]
msg := xref[idx+1:]
for _, file := range g.plugin.Files {
if strings.Compare(pkg, *(file.Proto.Package)) != 0 {
continue
}
if ident, err := getGoIdentByMessage(file.Messages, msg); err == nil {
return ident, nil
}
}
return protogen.GoIdent{}, fmt.Errorf("not found")
}
func getGoIdentByMessage(messages []*protogen.Message, msg string) (protogen.GoIdent, error) {
for _, message := range messages {
if strings.Compare(msg, message.GoIdent.GoName) == 0 {
return message.GoIdent, nil
}
if len(message.Messages) > 0 {
if ident, err := getGoIdentByMessage(message.Messages, msg); err == nil {
return ident, nil
}
}
}
return protogen.GoIdent{}, fmt.Errorf("not found")
}