diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 00a4c75..7a0b07a 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,7 +1,6 @@ name: Build on: - - push - pull_request jobs: @@ -40,3 +39,20 @@ jobs: args: release --skip-publish --rm-dist --snapshot - name: Image run: make build-image + + BuildEmbedUI: + runs-on: ubuntu-20.04 + steps: + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.18.x + - uses: actions/checkout@v3.0.0 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: 18.x + cache: 'npm' + cache-dependency-path: console/atest-ui/package-lock.json + - name: Build + run: make build-embed-ui diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 8c953b8..cc2ef61 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -24,6 +24,14 @@ jobs: uses: actions/setup-go@v3 with: go-version: 1.18 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: 18.x + cache: 'npm' + cache-dependency-path: console/atest-ui/package-lock.json + - name: Build + run: make build-embed-ui - name: Run GoReleaser uses: goreleaser/goreleaser-action@v2.9.1 with: diff --git a/Makefile b/Makefile index 4d09009..e5648dc 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,15 @@ build: mkdir -p bin rm -rf bin/atest go build -o bin/atest main.go +build-embed-ui: + cd console/atest-ui && npm i && npm run build-only + cp console/atest-ui/dist/index.html cmd/data/index.html + cp console/atest-ui/dist/assets/*.js cmd/data/index.js + cp console/atest-ui/dist/assets/*.css cmd/data/index.css + go build -ldflags "-w -s" -o bin/atest main.go + # echo '' > cmd/data/index.html + # echo '' > cmd/data/index.js + # echo '' > cmd/data/index.css goreleaser: goreleaser build --rm-dist --snapshot build-image: @@ -9,7 +18,7 @@ build-image: run-image: docker run -p 7070:7070 -p 8080:8080 ghcr.io/linuxsuren/api-testing:dev run-server: - go run . server --local-storage 'sample/*.yaml' + go run . server --local-storage 'sample/*.yaml' --console-path console/atest-ui/dist copy: build sudo cp bin/atest /usr/local/bin/ copy-restart: build diff --git a/cmd/data/index.css b/cmd/data/index.css new file mode 100644 index 0000000..e69de29 diff --git a/cmd/data/index.html b/cmd/data/index.html new file mode 100644 index 0000000..e69de29 diff --git a/cmd/data/index.js b/cmd/data/index.js new file mode 100644 index 0000000..e69de29 diff --git a/cmd/server.go b/cmd/server.go index 44d0465..5c2dae2 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -2,15 +2,21 @@ package cmd import ( + "bytes" "fmt" "log" "net" "net/http" "path" + "strings" + "time" + + _ "embed" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/linuxsuren/api-testing/pkg/server" "github.com/linuxsuren/api-testing/pkg/testing" + "github.com/linuxsuren/api-testing/pkg/util" "github.com/spf13/cobra" "google.golang.org/grpc" ) @@ -99,7 +105,27 @@ func frontEndHandlerWithLocation(consolePath string) func(w http.ResponseWriter, target = "/index.html" } - http.ServeFile(w, r, path.Join(consolePath, target)) + var content string + customHeader := map[string]string{} + switch { + case strings.HasSuffix(target, ".html"): + content = uiResourceIndex + case strings.HasSuffix(target, ".js"): + content = uiResourceJS + customHeader[util.ContentType] = "text/javascript; charset=utf-8" + case strings.HasSuffix(target, ".css"): + content = uiResourceCSS + customHeader[util.ContentType] = "text/css" + } + + if content != "" { + for k, v := range customHeader { + w.Header().Set(k, v) + } + http.ServeContent(w, r, "", time.Now(), bytes.NewReader([]byte(content))) + } else { + http.ServeFile(w, r, path.Join(consolePath, target)) + } } } @@ -125,3 +151,12 @@ func (s *fakeGRPCServer) Serve(net.Listener) error { func (s *fakeGRPCServer) RegisterService(desc *grpc.ServiceDesc, impl interface{}) { // Do nothing due to this is a fake method } + +//go:embed data/index.js +var uiResourceJS string + +//go:embed data/index.css +var uiResourceCSS string + +//go:embed data/index.html +var uiResourceIndex string diff --git a/cmd/server_test.go b/cmd/server_test.go index 6f4d764..5ad8f44 100644 --- a/cmd/server_test.go +++ b/cmd/server_test.go @@ -2,11 +2,13 @@ package cmd import ( "bytes" + "fmt" "net/http" "strings" "testing" "github.com/linuxsuren/api-testing/pkg/server" + "github.com/linuxsuren/api-testing/pkg/util" fakeruntime "github.com/linuxsuren/go-fake-runtime" "github.com/stretchr/testify/assert" ) @@ -51,20 +53,58 @@ func TestPrintProto(t *testing.T) { func TestFrontEndHandlerWithLocation(t *testing.T) { handler := frontEndHandlerWithLocation("testdata") - req, err := http.NewRequest("GET", "/", nil) - assert.NoError(t, err) + const expect404 = "404 page not found\n" - buf := new(bytes.Buffer) - handler(&fakeResponseWriter{buf: buf}, req, map[string]string{}) - assert.Equal(t, "404 page not found\n", buf.String()) + t.Run("404", func(t *testing.T) { + req, err := http.NewRequest("GET", "/", nil) + assert.NoError(t, err) + + resp := newFakeResponseWriter() + handler(resp, req, map[string]string{}) + assert.Equal(t, expect404, resp.GetBody().String()) + }) + + t.Run("get js", func(t *testing.T) { + req, err := http.NewRequest("GET", "/assets/index.js", nil) + assert.NoError(t, err) + defer func() { + uiResourceJS = "" + }() + + resp := newFakeResponseWriter() + + uiResourceJS = "js" + handler(resp, req, map[string]string{}) + assert.Equal(t, uiResourceJS, resp.GetBody().String()) + + fmt.Println(resp.Header()) + assert.Equal(t, "text/javascript; charset=utf-8", resp.Header().Get(util.ContentType)) + }) + + t.Run("get css", func(t *testing.T) { + req, err := http.NewRequest("GET", "/assets/index.css", nil) + assert.NoError(t, err) + + resp := newFakeResponseWriter() + handler(resp, req, map[string]string{}) + assert.Equal(t, expect404, resp.GetBody().String()) + }) } type fakeResponseWriter struct { - buf *bytes.Buffer + buf *bytes.Buffer + header http.Header +} + +func newFakeResponseWriter() *fakeResponseWriter { + return &fakeResponseWriter{ + buf: new(bytes.Buffer), + header: make(http.Header), + } } func (w *fakeResponseWriter) Header() http.Header { - return make(http.Header) + return w.header } func (w *fakeResponseWriter) Write(data []byte) (int, error) { return w.buf.Write(data) @@ -72,3 +112,6 @@ func (w *fakeResponseWriter) Write(data []byte) (int, error) { func (w *fakeResponseWriter) WriteHeader(int) { // do nothing due to this is a fake response writer } +func (w *fakeResponseWriter) GetBody() *bytes.Buffer { + return w.buf +}