Repository: zeromicro/go-zero
Pull request #2021 (2022-06-15 01:42:58)

feat: support build Dockerfile from current dir


Patch:
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 516d299b..43447473 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -35,11 +35,11 @@ jobs:
 
     steps:
     - name: Checkout repository
-      uses: actions/checkout@v2
+      uses: actions/checkout@v3
 
     # Initializes the CodeQL tools for scanning.
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@v1
+      uses: github/codeql-action/init@v2
       with:
         languages: ${{ matrix.language }}
         # If you wish to specify custom queries, you can do so here or in a config file.
@@ -50,7 +50,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
-      uses: github/codeql-action/autobuild@v1
+      uses: github/codeql-action/autobuild@v2
 
     # ℹ️ Command-line programs to run using the OS shell.
     # 📚 https://git.io/JvXDl
@@ -64,4 +64,4 @@ jobs:
     #   make release
 
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@v1
+      uses: github/codeql-action/analyze@v2
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index fc8dc0dc..7912ec60 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -18,7 +18,7 @@ jobs:
         id: go
 
       - name: Check out code into the Go module directory
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
 
       - name: Get dependencies
         run: |
@@ -46,7 +46,7 @@ jobs:
           go-version: ^1.15
 
       - name: Checkout codebase
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
 
       - name: Test
         run: |
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index be7d5159..bffa9c63 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -16,7 +16,7 @@ jobs:
           - goarch: "386"
             goos: darwin
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
       - uses: zeromicro/go-zero-release-action@master
         with:
           github_token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml
index 43a92646..415b567e 100644
--- a/.github/workflows/reviewdog.yml
+++ b/.github/workflows/reviewdog.yml
@@ -5,7 +5,7 @@ jobs:
     name: runner / staticcheck
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
       - uses: reviewdog/action-staticcheck@v1
         with:
           github_token: ${{ secrets.github_token }}
diff --git a/rest/httpc/requests.go b/rest/httpc/requests.go
index b6c9e861..b9c2d3bb 100644
--- a/rest/httpc/requests.go
+++ b/rest/httpc/requests.go
@@ -7,13 +7,20 @@ import (
 	"fmt"
 	"io"
 	"net/http"
+	"net/http/httptrace"
 	nurl "net/url"
 	"strings"
 
 	"github.com/zeromicro/go-zero/core/lang"
 	"github.com/zeromicro/go-zero/core/mapping"
+	"github.com/zeromicro/go-zero/core/trace"
 	"github.com/zeromicro/go-zero/rest/httpc/internal"
 	"github.com/zeromicro/go-zero/rest/internal/header"
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/codes"
+	"go.opentelemetry.io/otel/propagation"
+	semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
+	oteltrace "go.opentelemetry.io/otel/trace"
 )
 
 var interceptors = []internal.Interceptor{
@@ -150,17 +157,47 @@ func fillPath(u *nurl.URL, val map[string]interface{}) error {
 }
 
 func request(r *http.Request, cli client) (*http.Response, error) {
-	var respHandlers []internal.ResponseHandler
-	for _, interceptor := range interceptors {
+	tracer := otel.GetTracerProvider().Tracer(trace.TraceName)
+	propagator := otel.GetTextMapPropagator()
+
+	spanName := r.URL.Path
+	ctx, span := tracer.Start(
+		r.Context(),
+		spanName,
+		oteltrace.WithSpanKind(oteltrace.SpanKindClient),
+		oteltrace.WithAttributes(semconv.HTTPClientAttributesFromHTTPRequest(r)...),
+	)
+	defer span.End()
+
+	respHandlers := make([]internal.ResponseHandler, len(interceptors))
+	for i, interceptor := range interceptors {
 		var h internal.ResponseHandler
 		r, h = interceptor(r)
-		respHandlers = append(respHandlers, h)
+		respHandlers[i] = h
 	}
 
+	clientTrace := httptrace.ContextClientTrace(ctx)
+	if clientTrace != nil {
+		ctx = httptrace.WithClientTrace(ctx, clientTrace)
+	}
+
+	r = r.WithContext(ctx)
+	span.SetAttributes(semconv.HTTPClientAttributesFromHTTPRequest(r)...)
+	propagator.Inject(ctx, propagation.HeaderCarrier(r.Header))
+
 	resp, err := cli.do(r)
 	for i := len(respHandlers) - 1; i >= 0; i-- {
 		respHandlers[i](resp, err)
 	}
 
+	if err != nil {
+		span.RecordError(err)
+		span.SetStatus(codes.Error, err.Error())
+		return resp, err
+	}
+
+	span.SetAttributes(semconv.HTTPAttributesFromHTTPStatusCode(resp.StatusCode)...)
+	span.SetStatus(semconv.SpanStatusFromHTTPStatusCode(resp.StatusCode))
+
 	return resp, err
 }
diff --git a/tools/goctl/docker/cmd.go b/tools/goctl/docker/cmd.go
index 00ed6d59..2a82d20a 100644
--- a/tools/goctl/docker/cmd.go
+++ b/tools/goctl/docker/cmd.go
@@ -3,6 +3,7 @@ package docker
 import "github.com/spf13/cobra"
 
 var (
+	varExeName       string
 	varStringGo      string
 	varStringBase    string
 	varIntPort       int
@@ -21,6 +22,7 @@ var (
 )
 
 func init() {
+	Cmd.Flags().StringVar(&varExeName, "exe", "", "The executable name in the built image")
 	Cmd.Flags().StringVar(&varStringGo, "go", "", "The file that contains main function")
 	Cmd.Flags().StringVar(&varStringBase, "base", "scratch", "The base image to build the docker image, default scratch")
 	Cmd.Flags().IntVar(&varIntPort, "port", 0, "The port to expose, default none")
diff --git a/tools/goctl/docker/docker.go b/tools/goctl/docker/docker.go
index 0dbc42f4..15ad115a 100644
--- a/tools/goctl/docker/docker.go
+++ b/tools/goctl/docker/docker.go
@@ -4,6 +4,7 @@ import (
 	"errors"
 	"fmt"
 	"os"
+	"path"
 	"path/filepath"
 	"strings"
 	"text/template"
@@ -24,6 +25,7 @@ const (
 // Docker describes a dockerfile
 type Docker struct {
 	Chinese     bool
+	GoMainFrom  string
 	GoRelPath   string
 	GoFile      string
 	ExeFile     string
@@ -65,11 +67,7 @@ func dockerCommand(_ *cobra.Command, _ []string) (err error) {
 		pathx.RegisterGoctlHome(home)
 	}
 
-	if len(goFile) == 0 {
-		return errors.New("-go can't be empty")
-	}
-
-	if !pathx.FileExists(goFile) {
+	if len(goFile) > 0 && !pathx.FileExists(goFile) {
 		return fmt.Errorf("file %q not found", goFile)
 	}
 
@@ -126,9 +124,13 @@ func findConfig(file, dir string) (string, error) {
 }
 
 func generateDockerfile(goFile, base string, port int, version, timezone string, args ...string) error {
-	projPath, err := getFilePath(filepath.Dir(goFile))
-	if err != nil {
-		return err
+	var projPath string
+	var err error
+	if len(goFile) > 0 {
+		projPath, err = getFilePath(filepath.Dir(goFile))
+		if err != nil {
+			return err
+		}
 	}
 
 	if len(projPath) == 0 {
@@ -151,12 +153,27 @@ func generateDockerfile(goFile, base string, port int, version, timezone string,
 		builder.WriteString(`, "` + arg + `"`)
 	}
 
+	var exeName string
+	if len(varExeName) > 0 {
+		exeName = varExeName
+	} else if len(goFile) > 0 {
+		exeName = pathx.FileNameWithoutExt(filepath.Base(goFile))
+	} else {
+		absPath, err := filepath.Abs(projPath)
+		if err != nil {
+			return err
+		}
+
+		exeName = filepath.Base(absPath)
+	}
+
 	t := template.Must(template.New("dockerfile").Parse(text))
 	return t.Execute(out, Docker{
 		Chinese:     env.InChina(),
+		GoMainFrom:  path.Join(projPath, goFile),
 		GoRelPath:   projPath,
 		GoFile:      goFile,
-		ExeFile:     pathx.FileNameWithoutExt(filepath.Base(goFile)),
+		ExeFile:     exeName,
 		BaseImage:   base,
 		HasPort:     port > 0,
 		Port:        port,
diff --git a/tools/goctl/docker/docker.tpl b/tools/goctl/docker/docker.tpl
index 250a9dd4..d1b5ff44 100644
--- a/tools/goctl/docker/docker.tpl
+++ b/tools/goctl/docker/docker.tpl
@@ -15,7 +15,7 @@ ADD go.sum .
 RUN go mod download
 COPY . .
 {{if .Argument}}COPY {{.GoRelPath}}/etc /app/etc
-{{end}}RUN go build -ldflags="-s -w" -o /app/{{.ExeFile}} {{.GoRelPath}}/{{.GoFile}}
+{{end}}RUN go build -ldflags="-s -w" -o /app/{{.ExeFile}} {{.GoMainFrom}}
 
 
 FROM {{.BaseImage}}


Test patch:
diff --git a/rest/httpc/requests_test.go b/rest/httpc/requests_test.go
index c6160c48..e8edf2b1 100644
--- a/rest/httpc/requests_test.go
+++ b/rest/httpc/requests_test.go
@@ -4,15 +4,25 @@ import (
 	"context"
 	"net/http"
 	"net/http/httptest"
+	"net/http/httptrace"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	ztrace "github.com/zeromicro/go-zero/core/trace"
 	"github.com/zeromicro/go-zero/rest/httpx"
 	"github.com/zeromicro/go-zero/rest/internal/header"
 	"github.com/zeromicro/go-zero/rest/router"
+	"go.opentelemetry.io/otel/trace"
 )
 
 func TestDoRequest(t *testing.T) {
+	ztrace.StartAgent(ztrace.Config{
+		Name:     "go-zero-test",
+		Endpoint: "http://localhost:14268/api/traces",
+		Batcher:  "jaeger",
+		Sampler:  1.0,
+	})
+
 	svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 	}))
 	defer svr.Close()
@@ -21,6 +31,8 @@ func TestDoRequest(t *testing.T) {
 	resp, err := DoRequest(req)
 	assert.Nil(t, err)
 	assert.Equal(t, http.StatusOK, resp.StatusCode)
+	spanContext := trace.SpanContextFromContext(resp.Request.Context())
+	assert.True(t, spanContext.IsValid())
 }
 
 func TestDoRequest_NotFound(t *testing.T) {
@@ -187,3 +199,17 @@ func TestDo_Json(t *testing.T) {
 	_, err = Do(context.Background(), http.MethodPost, svr.URL+"/nodes/:key", data)
 	assert.NotNil(t, err)
 }
+
+func TestDo_WithClientHttpTrace(t *testing.T) {
+	svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
+	defer svr.Close()
+
+	_, err := Do(httptrace.WithClientTrace(context.Background(),
+		&httptrace.ClientTrace{
+			DNSStart: func(info httptrace.DNSStartInfo) {
+				assert.Equal(t, "localhost", info.Host)
+			},
+		}), http.MethodGet, svr.URL, nil)
+	assert.Nil(t, err)
+
+}