From ad63b2db983f6c2ec2b317c47d1ed08b12203846 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Wed, 2 Aug 2023 00:52:06 +0200 Subject: [PATCH] Add CLI tool to inspect OpenAPI schemas (#39) --- .github/workflows/release-assets.yml | 92 ++++++++++++++++++++++++++++ Makefile | 6 ++ README.md | 69 ++++++++++++++------- cmd/swgui/swgui.go | 79 ++++++++++++++++++++++++ go.mod | 2 +- go.sum | 12 ++-- 6 files changed, 231 insertions(+), 29 deletions(-) create mode 100644 .github/workflows/release-assets.yml create mode 100644 cmd/swgui/swgui.go diff --git a/.github/workflows/release-assets.yml b/.github/workflows/release-assets.yml new file mode 100644 index 0000000..b7b3f18 --- /dev/null +++ b/.github/workflows/release-assets.yml @@ -0,0 +1,92 @@ +# This script is provided by github.com/bool64/dev. + +# This script uploads application binaries as GitHub release assets. +name: release-assets +on: + release: + types: + - created +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GO_VERSION: 1.20.x +jobs: + build: + name: Upload Release Assets + runs-on: ubuntu-latest + steps: + - name: Install Go stable + if: env.GO_VERSION != 'tip' + uses: actions/setup-go@v4 + with: + go-version: ${{ env.GO_VERSION }} + - name: Install Go tip + if: env.GO_VERSION == 'tip' + run: | + curl -sL https://storage.googleapis.com/go-build-snap/go/linux-amd64/$(git ls-remote https://github.com/golang/go.git HEAD | awk '{print $1;}').tar.gz -o gotip.tar.gz + ls -lah gotip.tar.gz + mkdir -p ~/sdk/gotip + tar -C ~/sdk/gotip -xzf gotip.tar.gz + ~/sdk/gotip/bin/go version + echo "PATH=$HOME/go/bin:$HOME/sdk/gotip/bin/:$PATH" >> $GITHUB_ENV + - name: Checkout code + uses: actions/checkout@v3 + - name: Build artifacts + run: | + make release-assets + - name: Upload linux_amd64.tar.gz + if: hashFiles('linux_amd64.tar.gz') != '' + uses: actions/upload-release-asset@v1 + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ./linux_amd64.tar.gz + asset_name: linux_amd64.tar.gz + asset_content_type: application/tar+gzip + - name: Upload linux_amd64_dbg.tar.gz + if: hashFiles('linux_amd64.tar.gz') != '' + uses: actions/upload-release-asset@v1 + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ./linux_amd64_dbg.tar.gz + asset_name: linux_amd64_dbg.tar.gz + asset_content_type: application/tar+gzip + - name: Upload linux_arm64.tar.gz + if: hashFiles('linux_arm64.tar.gz') != '' + uses: actions/upload-release-asset@v1 + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ./linux_arm64.tar.gz + asset_name: linux_arm64.tar.gz + asset_content_type: application/tar+gzip + - name: Upload linux_arm.tar.gz + if: hashFiles('linux_arm.tar.gz') != '' + uses: actions/upload-release-asset@v1 + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ./linux_arm.tar.gz + asset_name: linux_arm.tar.gz + asset_content_type: application/tar+gzip + - name: Upload darwin_amd64.tar.gz + if: hashFiles('darwin_amd64.tar.gz') != '' + uses: actions/upload-release-asset@v1 + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ./darwin_amd64.tar.gz + asset_name: darwin_amd64.tar.gz + asset_content_type: application/tar+gzip + - name: Upload darwin_arm64.tar.gz + if: hashFiles('darwin_arm64.tar.gz') != '' + uses: actions/upload-release-asset@v1 + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ./darwin_arm64.tar.gz + asset_name: darwin_arm64.tar.gz + asset_content_type: application/tar+gzip + - name: Upload windows_amd64.zip + if: hashFiles('windows_amd64.zip') != '' + uses: actions/upload-release-asset@v1 + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ./windows_amd64.zip + asset_name: windows_amd64.zip + asset_content_type: application/zip + diff --git a/Makefile b/Makefile index 78059aa..7b6ca5b 100644 --- a/Makefile +++ b/Makefile @@ -27,9 +27,15 @@ ifeq ($(DEVGO_PATH),) endif endif +export CGO_ENABLED = 0 +BUILD_LDFLAGS=-s -w +BUILD_PKG = ./cmd/swgui + -include $(DEVGO_PATH)/makefiles/main.mk -include $(DEVGO_PATH)/makefiles/lint.mk -include $(DEVGO_PATH)/makefiles/reset-ci.mk +-include $(DEVGO_PATH)/makefiles/release-assets.mk +-include $(DEVGO_PATH)/makefiles/build.mk # Add your custom targets here. diff --git a/README.md b/README.md index 197853b..b329b27 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ Package `swgui` (Swagger UI) provides HTTP handler to serve Swagger UI. All assets are embedded in Go source code, so just build and run. -### V3 +### V5 -Static assets for `v3` are built from Swagger -UI [v3.52.5](https://github.com/swagger-api/swagger-ui/releases/tag/v3.52.5). +Static assets for `v5` are built from Swagger +UI [v5.1.3](https://github.com/swagger-api/swagger-ui/releases/tag/v5.1.3). -[CDN-based](https://cdnjs.com/libraries/swagger-ui) `v3cdn` uses Swagger -UI [v3.52.4](https://github.com/swagger-api/swagger-ui/releases/tag/v3.52.4). +[CDN-based](https://cdnjs.com/libraries/swagger-ui) `v5cdn` uses Swagger +UI [v5.1.3](https://github.com/swagger-api/swagger-ui/releases/tag/v5.1.3). ### V4 @@ -21,14 +21,13 @@ UI [v4.19.1](https://github.com/swagger-api/swagger-ui/releases/tag/v4.19.1). [CDN-based](https://cdnjs.com/libraries/swagger-ui) `v4cdn` uses Swagger UI [v4.19.1](https://github.com/swagger-api/swagger-ui/releases/tag/v4.19.1). -### V5 - -Static assets for `v5` are built from Swagger -UI [v5.1.3](https://github.com/swagger-api/swagger-ui/releases/tag/v5.1.3). +### V3 -[CDN-based](https://cdnjs.com/libraries/swagger-ui) `v5cdn` uses Swagger -UI [v5.1.3](https://github.com/swagger-api/swagger-ui/releases/tag/v5.1.3). +Static assets for `v3` are built from Swagger +UI [v3.52.5](https://github.com/swagger-api/swagger-ui/releases/tag/v3.52.5). +[CDN-based](https://cdnjs.com/libraries/swagger-ui) `v3cdn` uses Swagger +UI [v3.52.4](https://github.com/swagger-api/swagger-ui/releases/tag/v3.52.4). ## How to use @@ -38,17 +37,16 @@ package main import ( "net/http" - "github.com/swaggest/swgui/v3emb" // For go1.16 or later. - // "github.com/swaggest/swgui/v3" // For go1.15 and below. + "github.com/swaggest/swgui/v5emb" ) func main() { - http.Handle("/", v3.NewHandler("My API", "/swagger.json", "/")) - http.ListenAndServe(":8080", nil) + http.Handle("/", v5emb.NewHandler("My API", "/swagger.json", "/")) + _ = http.ListenAndServe(":8080", nil) } ``` -If you use `go1.16` or later, you can import natively embedded assets with `"github.com/swaggest/swgui/v3emb"`, it may +If you use `go1.16` or later, you can import natively embedded assets with `"github.com/swaggest/swgui/v5emb"`, it may help to lower application memory usage. ## Use CDN for assets @@ -59,12 +57,41 @@ Also you can use `swguicdn` build tag to enable CDN mode for `github.com/swagges Be aware that CDN mode may be considered inappropriate for security or networking reasons. -## Run as standalone server +## Documentation viewer CLI tool + +Install `swgui`. + +``` +go install github.com/swaggest/swgui/cmd/swgui@latest +``` + +Or download binary from [releases](https://github.com/swaggest/swgui/releases). -Install `swgui-server` +### Linux AMD64 - go get github.com/swaggest/swgui/... +``` +wget https://github.com/swaggest/swgui/releases/latest/download/linux_amd64.tar.gz && tar xf linux_amd64.tar.gz && rm linux_amd64.tar.gz +./swgui -version +``` -Start server +### Macos Intel - swgui-server -port 8080 +``` +wget https://github.com/swaggest/swgui/releases/latest/download/darwin_amd64.tar.gz && tar xf darwin_amd64.tar.gz && rm darwin_amd64.tar.gz +codesign -s - ./swgui +./swgui -version +``` + +### Macos Apple Silicon (M1, etc...) + +``` +wget https://github.com/swaggest/swgui/releases/latest/download/darwin_arm64.tar.gz && tar xf darwin_arm64.tar.gz && rm darwin_arm64.tar.gz +codesign -s - ./swgui +./swgui -version +``` + +Open spec file. + +``` +swgui my-openapi.yaml +``` diff --git a/cmd/swgui/swgui.go b/cmd/swgui/swgui.go new file mode 100644 index 0000000..001e104 --- /dev/null +++ b/cmd/swgui/swgui.go @@ -0,0 +1,79 @@ +// Package main provides CLI tool to inspect OpenAPI schemas with Swagger UI. +package main + +import ( + "flag" + "fmt" + "log" + "net/http" + "net/http/httptest" + "os/exec" + "path" + "runtime" + + "github.com/bool64/dev/version" + swgui "github.com/swaggest/swgui/v5emb" +) + +func main() { + ver := flag.Bool("version", false, "Show version and exit.") + flag.Parse() + + if *ver { + fmt.Printf("%s, Swagger UI %s\n", version.Info().Version, "v5.1.3") + + return + } + + if flag.NArg() < 1 { + fmt.Println("Usage: swgui ") + flag.PrintDefaults() + + return + } + + filePathToSchema := flag.Arg(0) + urlToSchema := "/" + path.Base(filePathToSchema) + + swh := swgui.NewHandler(filePathToSchema, urlToSchema, "/") + hh := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + if r.URL.Path == urlToSchema { + http.ServeFile(rw, r, filePathToSchema) + } + + swh.ServeHTTP(rw, r) + }) + + srv := httptest.NewServer(hh) + + log.Println("Starting Swagger UI server at", srv.URL) + log.Println("Press Ctrl+C to stop") + + if err := open(srv.URL); err != nil { + log.Println("open browser:", err.Error()) + } + + <-make(chan struct{}) +} + +// open opens the specified URL in the default browser of the user. +func open(url string) error { + var ( + cmd string + args []string + ) + + switch runtime.GOOS { + case "windows": + cmd = "cmd" + args = []string{"/c", "start"} + case "darwin": + cmd = "open" + default: // "linux", "freebsd", "openbsd", "netbsd" + cmd = "xdg-open" + } + + args = append(args, url) + + return exec.Command(cmd, args...).Start() //nolint:gosec +} diff --git a/go.mod b/go.mod index 0a3e3fb..9ff546a 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bool64/dev v0.2.29 github.com/shurcooL/httpgzip v0.0.0-20190720172056-320755c1c1b0 github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 - github.com/vearutop/statigz v1.2.0 + github.com/vearutop/statigz v1.4.0 ) require ( diff --git a/go.sum b/go.sum index 5b88659..7f3ac0d 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,6 @@ -github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/bool64/dev v0.2.22/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= -github.com/bool64/dev v0.2.27 h1:mFT+B74mFVgUeUmm/EbfM6ELPA55lEXBjQ/AOHCwCOc= -github.com/bool64/dev v0.2.27/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/bool64/dev v0.2.28/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/bool64/dev v0.2.29 h1:x+syGyh+0eWtOzQ1ItvLzOGIWyNWnyjXpHIcpF2HvL4= github.com/bool64/dev v0.2.29/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= @@ -18,8 +16,8 @@ github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJV github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/vearutop/statigz v1.2.0 h1:GGBHsDF3KnJBE6UmhvYdRg58ok9boQX/R+nUGRWPMXM= -github.com/vearutop/statigz v1.2.0/go.mod h1:jqlOPvLAdiQktMtYAkyguI3Ee0FA26iXKeEx2pS5l88= +github.com/vearutop/statigz v1.4.0 h1:RQL0KG3j/uyA/PFpHeZ/L6l2ta920/MxlOAIGEOuwmU= +github.com/vearutop/statigz v1.4.0/go.mod h1:LYTolBLiz9oJISwiVKnOQoIwhO1LWX1A7OECawGS8XE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=