diff --git a/.env b/.env new file mode 100644 index 0000000..aa936d8 --- /dev/null +++ b/.env @@ -0,0 +1,4 @@ +CLIENT_ORIGINS= +GIN_MODE=release +SPA_PATH=/app/html +SPA_CACHE_DISABLED=false diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index f6ba1db..3065ba4 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -10,8 +10,12 @@ env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} +concurrency: + group: ${{ github.repository }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: - install-and-test: + backend: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -23,35 +27,93 @@ jobs: cache: true # Used to specify the path to a dependency file - go.sum cache-dependency-path: go.sum + - name: Setup dependencies + run: make setup-backend env + - name: Generate code from spec + run: make generate-backend + - name: Run go vet + run: go vet ./... + - name: Run backend tests + run: make test-backend-cov + - uses: actions/upload-artifact@v3 + with: + name: backend-reports + path: reports + frontend: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 - name: Setup Node.js environment uses: actions/setup-node@v3.5.1 with: # File containing the version Spec of the version to use. Examples: .nvmrc, .node-version, .tool-versions. - node-version-file: .nvmrc + node-version-file: web/app/.nvmrc # Used to specify a package manager for caching in the default directory. Supported values: npm, yarn, pnpm. cache: yarn - - uses: satackey/action-docker-layer-caching@v0.0.11 - continue-on-error: true + cache-dependency-path: web/app/yarn.lock - name: Setup dependencies - run: make setup + run: make setup-frontend env + - name: Generate code from spec + run: make generate-frontend - name: Run frontend tests - run: yarn test - - name: Run backend tests - run: go test ./... + run: make test-frontend + - uses: actions/upload-artifact@v3 + with: + name: frontend-reports + path: reports + docker: + runs-on: ubuntu-latest + needs: + - frontend + - backend + steps: + - uses: actions/checkout@v3 + - uses: docker/setup-buildx-action@v2 - name: Build Docker image uses: docker/build-push-action@v3.2.0 with: context: . - + cache-from: type=gha + cache-to: type=gha,mode=max + sonar: + runs-on: ubuntu-latest + needs: + - publish + if: ${{ always() && (needs.publish.result == 'skipped' || needs.publish.result == 'success') }} + steps: + - uses: actions/checkout@v3 + with: + # Disabling shallow clone is recommended for improving relevancy of reporting + fetch-depth: 0 + ref: ${{ github.ref == 'refs/heads/main' && 'main' || '' }} + - uses: actions/download-artifact@v3 + with: + name: frontend-reports + path: reports + - uses: actions/download-artifact@v3 + with: + name: backend-reports + path: reports + - name: SonarCloud Scan + uses: sonarsource/sonarcloud-github-action@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} publish: - needs: install-and-test + needs: + - docker if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest permissions: - contents: write packages: write + contents: write steps: - uses: actions/checkout@v3 + with: + fetch-depth: 0 + # Needed to bypass branch protections when publishing a release + token: ${{ secrets.GH_TOKEN }} + - uses: docker/setup-buildx-action@v2 - name: Log in to the Container registry uses: docker/login-action@v2.1.0 with: @@ -59,17 +121,36 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - uses: satackey/action-docker-layer-caching@v0.0.11 - continue-on-error: true - - name: Conventional Changelog Action - id: semver + id: changelog uses: TriPSs/conventional-changelog-action@v3 with: + git-user-name: github-actions + git-user-email: actions@github.com fallback-version: 0.0.0 github-token: ${{ secrets.GITHUB_TOKEN }} + skip-commit: true + version-file: web/app/package.json git-push: false + - name: Update version field in OAPI spec file + if: ${{ steps.changelog.outputs.skipped == 'false' }} + uses: mikefarah/yq@v4.30.4 + with: + cmd: yq -i '.info.version = "${{ steps.changelog.outputs.version }}"' 'api/openapi.yaml' + + - name: Update version field of sonar-project.properties + if: ${{ steps.changelog.outputs.skipped == 'false' }} + run: sed -i "s/sonar.projectVersion=.*/sonar.projectVersion=${{ steps.changelog.outputs.version }}/" "sonar-project.properties" + + - name: Commit release + if: ${{ steps.changelog.outputs.skipped == 'false' }} + run: | + git config --global user.name "${GITHUB_ACTOR}" + git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com" + git add . + git commit -m "chore(release): ${{ steps.changelog.outputs.tag }} [skip ci]" + - name: Extract metadata (tags, labels) for Docker id: meta if: ${{ steps.changelog.outputs.skipped == 'false' }} @@ -78,7 +159,7 @@ jobs: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }} - type=semver,pattern={{version}},value=${{ steps.semver.outputs.tag }} + type=semver,pattern={{version}},value=${{ steps.changelog.outputs.tag }} # type=ref,event=branch # type=ref,event=pr @@ -88,6 +169,8 @@ jobs: with: context: . push: true + cache-from: type=gha + cache-to: type=gha,mode=max tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} @@ -102,7 +185,7 @@ jobs: with: allowUpdates: true draft: false - name: ${{ steps.semver.outputs.tag }} - tag: ${{ steps.semver.outputs.tag }} - body: ${{ steps.semver.outputs.clean_changelog }} + name: ${{ steps.changelog.outputs.tag }} + tag: ${{ steps.changelog.outputs.tag }} + body: ${{ steps.changelog.outputs.clean_changelog }} token: ${{ github.token }} diff --git a/.gitignore b/.gitignore index 28ac589..09e3943 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,7 @@ coverage !.vscode/extensions.json # dependencies -/node_modules +**/node_modules /.pnp .pnp.js @@ -25,7 +25,7 @@ coverage /coverage # production -/build +**/build # misc .DS_Store @@ -34,6 +34,9 @@ coverage .env.test.local .env.production.local -npm-debug.log* -yarn-debug.log* -yarn-error.log* +**/npm-debug.log* +**/yarn-debug.log* +**/yarn-error.log* + +**/generated/ +reports diff --git a/.minikube/go-chat-manager.yaml b/.minikube/go-chat-manager.yaml deleted file mode 100644 index 15603cb..0000000 --- a/.minikube/go-chat-manager.yaml +++ /dev/null @@ -1,79 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: chat-manager -# annotations: -# prometheus.io/scrape: "true" -# prometheus.io/path: "/prometheus" -# prometheus.io/port: "8080" - name: chat-manager - namespace: default -spec: - selector: - app: chat-manager - ports: - - name: "http-port" - port: 80 - targetPort: http-port - type: NodePort - ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: chat-manager - namespace: default - labels: - app: chat-manager -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 1 - maxSurge: 1 - replicas: 1 - progressDeadlineSeconds: 100 - selector: - matchLabels: - app: chat-manager - template: - metadata: - labels: - app: chat-manager - spec: - containers: - - name: go-react-app - image: alexstojda/go-react-app:latest - imagePullPolicy: IfNotPresent - env: - - name: NAME - value: "value" - securityContext: - runAsUser: 1000 - runAsNonRoot: true - resources: - requests: - cpu: 100m - memory: 256Mi - limits: - cpu: 250m - memory: 256Mi - ports: - - containerPort: 8080 - name: http-port - livenessProbe: - httpGet: - path: /api/health - port: http-port - scheme: HTTP - initialDelaySeconds: 15 - timeoutSeconds: 10 - readinessProbe: - httpGet: - path: /api/health - port: http-port - scheme: HTTP - initialDelaySeconds: 15 - timeoutSeconds: 10 diff --git a/Dockerfile b/Dockerfile index 8dc4911..c19b759 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,54 @@ +####### +# Generate Axios Typescript API Client +####### +FROM openapitools/openapi-generator-cli:v6.6.0 AS node-gen + +COPY api/.openapi-generator-ignore /out/ +COPY api/openapi.yaml /api/ + +RUN /usr/local/bin/docker-entrypoint.sh generate \ +-i /api/openapi.yaml \ +-g typescript-axios \ +-o /out + +####### +# Build SPA +####### FROM node:18-alpine AS node-dev -RUN mkdir -p /usr/src/app -WORKDIR /usr/src/app -COPY package.json /usr/src/app +RUN mkdir -p /app +WORKDIR /app + +COPY web/app/package.json /app RUN yarn -COPY . /usr/src/app + +COPY web/app/ /app +COPY --from=node-gen /out/ /app/src/api/generated + RUN yarn build -ENTRYPOINT ["npm"] +ENTRYPOINT ["yarn"] -FROM golang:1.19-alpine AS go-dev +####### +# Golang shared base image +####### +FROM golang:1.22-alpine AS go-base + +####### +# Generate Golang API Server +####### +FROM go-base AS go-gen + +RUN go install "github.com/deepmap/oapi-codegen/cmd/oapi-codegen@v1.13.0" +RUN mkdir -p /out + +COPY api /api +RUN /go/bin/oapi-codegen -config /api/oapi-codegen.config.yaml /api/openapi.yaml > /out/openapi.gen.go + +####### +# Build API Server +####### +FROM go-base AS go-dev ENV CGO_ENABLED=0 \ GOOS=linux \ @@ -29,25 +68,31 @@ COPY --chown=golang:root go.mod go.sum Makefile ./ RUN make mod -COPY --chown=golang:root . ./ -RUN go build -v -o go-react-app ./cmd/go-react-app/ +COPY --chown=golang:root main.go ./ +COPY --chown=golang:root internal ./internal +COPY --from=go-gen /out/ internal/app/generated/ +RUN go build -v -o pinman main.go ENTRYPOINT ["make"] -#CMD ["test"] - -### +CMD ["test"] +####### +# Final production image with all assets +####### FROM scratch AS prod COPY --from=go-dev /etc/passwd /etc/group /etc/ COPY --from=go-dev /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ # Kube crashes if there isn't a tmp directory to write error logs to COPY --from=go-dev --chown=golang:root /tmp /tmp -COPY --from=go-dev --chown=golang:root /app/go-react-app /app/ -COPY --from=node-dev --chown=golang:root /usr/src/app/build /app/html +COPY --from=go-dev --chown=golang:root /app/pinman /app/ +COPY --from=node-dev --chown=golang:root /app/build /app/html + +COPY --chown=golang:root .env /app/ USER golang:root EXPOSE 8080 ENV SPA_PATH=/app/html -ENTRYPOINT ["/app/go-react-app"] +WORKDIR /app +ENTRYPOINT ["./pinman"] diff --git a/Makefile b/Makefile index d5a4bfe..08b2153 100644 --- a/Makefile +++ b/Makefile @@ -1,33 +1,77 @@ -setup: mod - yarn install +FRONTEND_DIR = './web/app' + +setup: setup-frontend setup-backend + +setup-frontend: + @cd $(FRONTEND_DIR) && yarn + +setup-backend: mod mod: - go mod download + @go mod download + +env: env-local + +env-local: + @cp .env .env.local + +clean: + @rm -rf $(FRONTEND_DIR)/build + +generate: generate-backend generate-frontend + +generate-frontend: + @docker compose up --remove-orphans --build -d openapi-client + @rm -rf web/app/src/api/generated && true + @docker compose cp openapi-client:/out web/app/src/api/generated + @docker compose stop openapi-client + +generate-backend: + @docker compose up --remove-orphans --build -d openapi-server + @rm -rf internal/app/generated && true + @docker compose cp openapi-server:/out internal/app/generated + @docker compose stop openapi-server build: build-backend build-frontend build-backend: - mkdir -p ./build - go build -v -o ./build/go-react-app ./cmd/go-react-app/ + @mkdir -p ./build + @go build -v -o ./build/pinman main.go build-frontend: - yarn build + @cd $(FRONTEND_DIR) && yarn build -run: build-frontend - SPA_PATH=./build go run cmd/go-react-app/main.go +run: clean generate build-frontend + @SPA_PATH=./web/app/build go run main.go run-backend: - go run cmd/go-react-app/main.go + @ENV_FILE=.env.local go run main.go + +run-database: + @docker compose up -d postgres run-frontend: - REACT_APP_API_HOST=http://localhost:8080 yarn start -# -#test: -# @go test ./... -# -#test-cov: -# mkdir -p coverage -# @go test -covermode=atomic -coverprofile=./coverage/coverage.txt ./... -# @go get github.com/axw/gocov/gocov -# @go get github.com/AlekSi/gocov-xml -# @gocov convert ./coverage/coverage.txt | gocov-xml > ./coverage/coverage.xml \ No newline at end of file + @cd $(FRONTEND_DIR) && REACT_APP_API_HOST=http://localhost:8080/api yarn start + +test: test-backend test-frontend + +test-setup: + @go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo + +test-frontend: + @cd $(FRONTEND_DIR) && yarn test + @rm -rf ./reports/ts && true + @mkdir -p ./reports/ts + @mv -f $(FRONTEND_DIR)/coverage $(FRONTEND_DIR)/reports ./reports/ts/ + +test-backend: test-setup + @ginkgo ./... + +test-backend-cov: test-setup + @ginkgo --cover \ + --race \ + --json-report=report.json \ + --output-dir=reports/go \ + --skip-package generated \ + --skip-file mock \ + ./... diff --git a/api/.openapi-generator-ignore b/api/.openapi-generator-ignore new file mode 100644 index 0000000..b6d9932 --- /dev/null +++ b/api/.openapi-generator-ignore @@ -0,0 +1,27 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md + +git_push.sh +.gitignore +.npmignore diff --git a/api/oapi-codegen.config.yaml b/api/oapi-codegen.config.yaml new file mode 100644 index 0000000..32ba1a3 --- /dev/null +++ b/api/oapi-codegen.config.yaml @@ -0,0 +1,4 @@ +package: generated +generate: + gin-server: true + models: true diff --git a/api/openapi.yaml b/api/openapi.yaml new file mode 100644 index 0000000..c8c47cf --- /dev/null +++ b/api/openapi.yaml @@ -0,0 +1,50 @@ +openapi: 3.0.0 +info: + description: A Template for a an app with a Go backend and a React frontend + title: Go React App + version: 0.1.1 +servers: + - url: http://localhost:8080/api +paths: + /health: + get: + summary: Returns a health check message + responses: + '200': + $ref: '#/components/responses/HealthResponse' + /hello: + get: + summary: Returns a hello message + responses: + '200': + $ref: '#/components/responses/HelloResponse' +components: + responses: + HealthResponse: + description: A successful health response + content: + application/json: + schema: + type: object + properties: + status: + type: string + example: OK + x-oapi-codegen-extra-tags: + binding: required + required: + - status + HelloResponse: + description: A successful hello response + content: + application/json: + schema: + type: object + properties: + message: + type: string + example: Hello, World! + x-oapi-codegen-extra-tags: + binding: required + required: + - message diff --git a/cmd/go-react-app/main.go b/cmd/go-react-app/main.go deleted file mode 100644 index faca81e..0000000 --- a/cmd/go-react-app/main.go +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "os" - - "go-react-app/web" -) - -func main() { - spaPath := os.Getenv("SPA_PATH") - server := web.NewServer(spaPath) - - server.StartServer() -} diff --git a/deploy-minikube.sh b/deploy-minikube.sh deleted file mode 100644 index 670557f..0000000 --- a/deploy-minikube.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -set -o errexit -o nounset -cd `dirname $0` - -kubectl config use-context minikube - -eval $(minikube docker-env --shell=bash) - -docker-compose build go-react-app -kubectl delete deployment go-react-app || true -kubectl apply -f .minikube -kubectl rollout status deployment/go-react-app -kubectl get deployment go-react-app -echo "Deployed on $(minikube service go-react-app --url)" \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 47ce126..89ad9d9 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,24 +1,43 @@ -version: "3.4" - services: go-react-app-node-dev: build: context: . target: node-dev - image: alexstojda/go-react-app-development:${VERSION:-local} + image: alexstojda/go-react-app/node-dev:${VERSION:-local} go-react-app-go-dev: build: context: . target: go-dev - image: alexstojda/go-react-app-development:${VERSION:-local} + image: alexstojda/go-react-app/go-dev:${VERSION:-local} go-react-app: build: context: . target: prod - image: alexstojda/go-react-app:${VERSION:-local} - environment: - - NAME=value + args: + REACT_APP_API_HOST: http://localhost:8080 + env_file: + - ./.env.local ports: - - "8080" \ No newline at end of file + - "8080:8080" + image: alexstojda/go-react-app:${VERSION:-local} + + ## Code generation + openapi-server: + build: + context: . + target: go-gen + image: alexstojda/go-react-app/openapi-server:${VERSION:-local} + entrypoint: "sleep" + command: + - infinity + + openapi-client: + build: + context: . + target: node-gen + image: alexstojda/go-react-app/openapi-client:${VERSION:-local} + entrypoint: "sleep" + command: + - infinity diff --git a/go.mod b/go.mod index 93c620e..8b7d4df 100644 --- a/go.mod +++ b/go.mod @@ -1,40 +1,73 @@ module go-react-app -go 1.19 +go 1.22 + +toolchain go1.23.1 require ( + github.com/gin-contrib/cors v1.7.2 github.com/gin-contrib/logger v0.0.2 - github.com/gin-gonic/gin v1.6.3 + github.com/gin-gonic/gin v1.9.1 + github.com/mitchellh/mapstructure v1.5.0 github.com/rs/zerolog v1.20.0 - github.com/stretchr/testify v1.6.1 + github.com/spf13/viper v1.19.0 + github.com/stretchr/testify v1.9.0 github.com/zsais/go-gin-prometheus v0.1.0 ) +require ( + github.com/bytedance/sonic v1.11.6 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + golang.org/x/arch v0.7.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/text v0.17.0 // indirect +) + require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-contrib/static v0.0.1 - github.com/go-playground/locales v0.13.0 // indirect - github.com/go-playground/universal-translator v0.17.0 // indirect - github.com/go-playground/validator/v10 v10.2.0 // indirect - github.com/golang/protobuf v1.4.3 // indirect - github.com/json-iterator/go v1.1.10 // indirect - github.com/leodido/go-urn v1.2.0 // indirect - github.com/mattn/go-isatty v0.0.12 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.20.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.8.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.14.0 // indirect github.com/prometheus/procfs v0.2.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sirupsen/logrus v1.7.0 // indirect - github.com/ugorji/go/codec v1.1.7 // indirect - golang.org/x/sys v0.2.0 // indirect - google.golang.org/protobuf v1.23.0 // indirect - gopkg.in/yaml.v2 v2.3.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/sys v0.24.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 6e09ae6..40432de 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,10 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= +github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -32,6 +36,10 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -41,8 +49,9 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= @@ -55,34 +64,42 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw= +github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E= github.com/gin-contrib/logger v0.0.2 h1:qT6qOR9/mp9hrHAgTEVxpjvS3anQtiUTtzJhf+NlBQM= github.com/gin-contrib/logger v0.0.2/go.mod h1:Eca5g93bobBwWSNeuLdTqRvNK6btb3XSHdU9ePZ+toM= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-contrib/static v0.0.1 h1:JVxuvHPuUfkoul12N7dtQw7KRn/pSMq7Ue1Va9Swm1U= -github.com/gin-contrib/static v0.0.1/go.mod h1:CSxeF+wep05e0kCOsqWdAWbSszmc31zTIbD8TvWl7Hs= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= +github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -94,23 +111,26 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -138,6 +158,8 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= @@ -152,33 +174,41 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -190,12 +220,15 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= @@ -223,6 +256,8 @@ github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -230,8 +265,9 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= @@ -263,12 +299,18 @@ github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.16.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I= github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs= github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -281,23 +323,44 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -311,11 +374,18 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc= +golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -323,7 +393,11 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -349,6 +423,8 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -375,15 +451,18 @@ golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -402,7 +481,6 @@ golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -427,19 +505,25 @@ google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= @@ -448,14 +532,15 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/internal/app/api/api.go b/internal/app/api/api.go new file mode 100644 index 0000000..9317dbc --- /dev/null +++ b/internal/app/api/api.go @@ -0,0 +1,27 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "go-react-app/internal/app/api/health" + "go-react-app/internal/app/api/hello" +) + +type Server struct { + Hello *hello.Controller + Health *health.Controller +} + +func NewServer() *Server { + return &Server{ + Hello: hello.NewHello(), + Health: health.NewHealth(), + } +} + +func (s *Server) GetHealth(c *gin.Context) { + s.Health.Get(c) +} + +func (s *Server) GetHello(c *gin.Context) { + s.Hello.Get(c) +} diff --git a/internal/app/api/health/health.go b/internal/app/api/health/health.go new file mode 100644 index 0000000..d33ce67 --- /dev/null +++ b/internal/app/api/health/health.go @@ -0,0 +1,19 @@ +package health + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "go-react-app/internal/app/generated" +) + +type Controller struct{} + +func NewHealth() *Controller { + return &Controller{} +} + +func (h *Controller) Get(c *gin.Context) { + response := generated.HealthResponse{Status: "OK"} + c.JSON(http.StatusOK, response) +} diff --git a/web/api/health/health_test.go b/internal/app/api/health/health_test.go similarity index 82% rename from web/api/health/health_test.go rename to internal/app/api/health/health_test.go index 5b6191f..83ab025 100644 --- a/web/api/health/health_test.go +++ b/internal/app/api/health/health_test.go @@ -2,11 +2,13 @@ package health import ( "encoding/json" - "github.com/gin-gonic/gin" - "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" "testing" + + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" + "go-react-app/internal/app/generated" ) func TestHealth_Get(t *testing.T) { @@ -24,7 +26,7 @@ func TestHealth_Get(t *testing.T) { assert.Equal(t, resp.Code, 200) - data := Response{} + data := generated.HealthResponse{} err := json.Unmarshal(resp.Body.Bytes(), &data) if err != nil { @@ -32,5 +34,5 @@ func TestHealth_Get(t *testing.T) { t.Fatalf("Could not unmarshal response body. Got %s", resp.Body.String()) } - assert.Equal(t, data, Response{Status: "ok"}) + assert.Equal(t, data, generated.HealthResponse{Status: "OK"}) } diff --git a/internal/app/api/hello/hello.go b/internal/app/api/hello/hello.go new file mode 100644 index 0000000..ef562d4 --- /dev/null +++ b/internal/app/api/hello/hello.go @@ -0,0 +1,20 @@ +package hello + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "go-react-app/internal/app/generated" +) + +type Controller struct { +} + +func NewHello() *Controller { + return &Controller{} +} + +func (h *Controller) Get(c *gin.Context) { + response := generated.HelloResponse{Message: "Hello, World!"} + c.JSON(http.StatusOK, response) +} diff --git a/web/api/hello/hello_test.go b/internal/app/api/hello/hello_test.go similarity index 81% rename from web/api/hello/hello_test.go rename to internal/app/api/hello/hello_test.go index 1e6d9fb..21660c1 100644 --- a/web/api/hello/hello_test.go +++ b/internal/app/api/hello/hello_test.go @@ -2,11 +2,13 @@ package hello import ( "encoding/json" - "github.com/gin-gonic/gin" - "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" "testing" + + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" + "go-react-app/internal/app/generated" ) func TestHello_Get(t *testing.T) { @@ -24,7 +26,7 @@ func TestHello_Get(t *testing.T) { assert.Equal(t, resp.Code, 200) - data := Response{} + data := generated.HelloResponse{} err := json.Unmarshal(resp.Body.Bytes(), &data) if err != nil { @@ -32,5 +34,5 @@ func TestHello_Get(t *testing.T) { t.Fatalf("Could not unmarshal response body. Got %s", resp.Body.String()) } - assert.Equal(t, data, Response{Hello: "world"}) + assert.Equal(t, data, generated.HelloResponse{Message: "Hello, World!"}) } diff --git a/internal/app/config.go b/internal/app/config.go new file mode 100644 index 0000000..3d8789e --- /dev/null +++ b/internal/app/config.go @@ -0,0 +1,48 @@ +package app + +import ( + "os" + + "github.com/mitchellh/mapstructure" + "github.com/spf13/viper" +) + +type Config struct { + SPAPath string `mapstructure:"SPA_PATH"` + SPACacheDisabled bool `mapstructure:"SPA_CACHE_DISABLED"` + ClientOrigins []string `mapstructure:"CLIENT_ORIGINS"` +} + +func LoadConfig() (*Config, error) { + viper.AutomaticEnv() + viper.SetTypeByDefaultValue(true) + viper.SetConfigType("env") + if envFile := os.Getenv("ENV_FILE"); envFile != "" { + viper.SetConfigFile(envFile) + } else { + viper.SetConfigFile(".env") + } + + err := viper.ReadInConfig() + if err != nil { + return nil, err + } + + config := &Config{} + + // Silly bug in viper, it will only read ENV variables if they are defined in a .env file. + // So we manually tell viper to read all variables defined in the Config type. + envKeysMap := &map[string]interface{}{} + if err := mapstructure.Decode(config, &envKeysMap); err != nil { + return nil, err + } + for k := range *envKeysMap { + if bindErr := viper.BindEnv(k); bindErr != nil { + return nil, err + } + } + + err = viper.Unmarshal(config) + + return config, nil +} diff --git a/web/errors.go b/internal/app/errors.go similarity index 91% rename from web/errors.go rename to internal/app/errors.go index 9e318a3..349b7cb 100644 --- a/web/errors.go +++ b/internal/app/errors.go @@ -1,4 +1,4 @@ -package web +package app import "github.com/gin-gonic/gin" diff --git a/internal/app/server.go b/internal/app/server.go new file mode 100644 index 0000000..f22fbbe --- /dev/null +++ b/internal/app/server.go @@ -0,0 +1,132 @@ +package app + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gin-contrib/cors" + "github.com/gin-contrib/logger" + ginprometheus "github.com/zsais/go-gin-prometheus" + "go-react-app/internal/app/api" + "go-react-app/internal/app/api/health" + "go-react-app/internal/app/api/hello" + "go-react-app/internal/app/generated" + + "github.com/gin-gonic/gin" + "github.com/rs/zerolog/log" +) + +type Server struct { + SPAPath string + ClientOrigins []string + Health *health.Controller + Hello *hello.Controller +} + +func NewServer(spaPath string, clientOrigins []string) *Server { + return &Server{ + SPAPath: spaPath, + ClientOrigins: clientOrigins, + Health: health.NewHealth(), + Hello: hello.NewHello(), + } +} + +func (s *Server) StartServer() error { + router := gin.New() + + // Since we don't use any proxy, this feature can be disabled + err := router.SetTrustedProxies(nil) + if err != nil { + return fmt.Errorf("could not set trusted proxies: %v", err) + } + + router.Use(newGinLogger()) + router.Use(newCorsHandler(s.ClientOrigins)) + router.Use(errorHandler) + newPrometheus().Use(router) + + // API ROUTES + generated.RegisterHandlersWithOptions( + router, + api.NewServer(), + generated.GinServerOptions{ + BaseURL: "/api", + ErrorHandler: nil, + }) + + // SPA ROUTE + // Only loaded if SPAPath is defined. + if s.SPAPath != "" { + router.GET("/", func(c *gin.Context) { + c.Redirect(http.StatusPermanentRedirect, "/app") + }) + + log.Debug().Str("spaPath", s.SPAPath).Msg("SPA_PATH is set, will serve") + + router.Static("/app", s.SPAPath) + } + + router.NoRoute(func(c *gin.Context) { + if strings.HasPrefix(c.Request.URL.Path, "/app") && s.SPAPath != "" { + c.File(fmt.Sprintf("%s/index.html", s.SPAPath)) + return + } + + c.JSON(http.StatusNotFound, gin.H{"message": "Not found"}) + }) + + return router.Run() +} + +func newCorsHandler(clientOrigins []string) gin.HandlerFunc { + corsConfig := cors.DefaultConfig() + corsConfig.AllowOrigins = clientOrigins + if len(corsConfig.AllowOrigins) > 0 { + log.Info().Interface("allowedOrigins", corsConfig.AllowOrigins).Msg("CORS origins configured") + } + corsConfig.AllowCredentials = true + corsConfig.AllowHeaders = append( + corsConfig.AllowHeaders, + []string{ + "Authorization", + }..., + ) + + return cors.New(corsConfig) +} + +func newPrometheus() *ginprometheus.Prometheus { + prometheus := ginprometheus.NewPrometheus("gin") + + // Prevents high cardinality of metrics Source: https://github.com/zsais/go-gin-prometheus#preserving-a-low-cardinality-for-the-request-counter + prometheus.ReqCntURLLabelMappingFn = func(c *gin.Context) string { + url := c.Request.URL.Path // Query params are dropped here so there is not a metric for every permutation of query param usage on a route + + // If a route uses parameters, replace the parameter value with its name. Else there will be a metric for the route + // with every possible value of that parameter and this will cause performance issues in Prometheus. + // + // If your service uses route parameters, uncomment the for loop below and add a case for each parameter. The example case + // below works for routes with a parameter called 'name', like '/api/function/:name' + // -- + // for _, p := range c.Params { + // switch p.Key { + // case "name": + // url = strings.Replace(url, p.Value, ":name", 1) + // } + // } + return url + } + + return prometheus +} + +func newGinLogger() gin.HandlerFunc { + return logger.SetLogger(logger.Config{ + SkipPath: []string{ + "/health", + "/metrics", + }, + }) +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..48703ab --- /dev/null +++ b/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "github.com/gin-gonic/gin" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "go-react-app/internal/app" +) + +func main() { + zerolog.SetGlobalLevel(zerolog.InfoLevel) + if gin.IsDebugging() { + zerolog.SetGlobalLevel(zerolog.DebugLevel) + } + + config, err := app.LoadConfig() + if err != nil { + log.Fatal().Err(err).Msg("could not load config") + } + + server := app.NewServer(config.SPAPath, config.ClientOrigins) + + err = server.StartServer() + if err != nil { + log.Fatal().Err(err).Msg("could not start server") + } +} diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..ec22c88 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,15 @@ +# suppress inspection "UnusedProperty" for whole file +sonar.projectKey=alexstojda_go-react-app +sonar.organization=alexstojda +sonar.projectVersion=0.1.1 + +sonar.sources=internal,web,main.go +sonar.go.coverage.reportPaths=reports/go/coverprofile.out +sonar.go.tests.reportPath=reports/go/report.json + +sonar.test.inclusions=**/*_test.go,**/*.test.tsx,**/*.test.ts +sonar.test.exclusions=**/generated,**/mock_* +sonar.coverage.exclusions=**/generated,**/mock_* + +sonar.typescript.lcov.reportPaths=reports/ts/coverage/lcov.info +sonar.testExecutionReportPaths=reports/ts/reports/test-report.xml diff --git a/src/helpers/apiUrl.ts b/src/helpers/apiUrl.ts deleted file mode 100644 index 49e0316..0000000 --- a/src/helpers/apiUrl.ts +++ /dev/null @@ -1,10 +0,0 @@ -export default function apiUrl(path: string) { - if ( - process.env.REACT_APP_API_HOST !== undefined && - process.env.REACT_APP_API_HOST !== "" - ) { - return process.env.REACT_APP_API_HOST + path; - } else { - return path; - } -} diff --git a/web/api/health/health.go b/web/api/health/health.go deleted file mode 100644 index 1e81afa..0000000 --- a/web/api/health/health.go +++ /dev/null @@ -1,22 +0,0 @@ -package health - -import ( - "github.com/gin-gonic/gin" - "net/http" -) - -type Health struct { -} - -func NewHealth() *Health { - return &Health{} -} - -type Response struct { - Status string `json:"status"` -} - -func (h *Health) Get(c *gin.Context) { - response := Response{Status: "ok"} - c.JSON(http.StatusOK, response) -} diff --git a/web/api/hello/hello.go b/web/api/hello/hello.go deleted file mode 100644 index 48b7c07..0000000 --- a/web/api/hello/hello.go +++ /dev/null @@ -1,24 +0,0 @@ -package hello - -import ( - "github.com/gin-gonic/gin" - "net/http" -) - -type Hello struct { -} - -func NewHello() *Hello { - return &Hello{} -} - -type Response struct { - Hello string `json:"hello"` -} - -func (h *Hello) Get(c *gin.Context) { - response := Response{ - Hello: "world", - } - c.JSON(http.StatusOK, response) -} diff --git a/.nvmrc b/web/app/.nvmrc similarity index 100% rename from .nvmrc rename to web/app/.nvmrc diff --git a/package.json b/web/app/package.json similarity index 73% rename from package.json rename to web/app/package.json index 01456a6..a9f261f 100644 --- a/package.json +++ b/web/app/package.json @@ -2,6 +2,7 @@ "name": "my-app", "version": "0.0.0", "private": true, + "homepage": "/app", "dependencies": { "@babel/core": "^7.0.0-0", "@babel/plugin-syntax-flow": "^7.14.5", @@ -21,12 +22,26 @@ "typescript": "^4.4.2", "web-vitals": "^2.1.0" }, + "devDependencies": { + "jest-sonar-reporter": "^2.0.0" + }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", - "test": "react-scripts test", + "test": "react-scripts test --reporters=default --coverage --testResultsProcessor jest-sonar-reporter", "eject": "react-scripts eject" }, + "jest": { + "collectCoverageFrom": [ + "!**/generated/*.ts", + "!src/resources/*" + ] + }, + "jestSonar": { + "reportPath": "reports", + "reportFile": "test-report.xml", + "indent": 4 + }, "eslintConfig": { "extends": [ "react-app", diff --git a/public/favicon.ico b/web/app/public/favicon.ico similarity index 100% rename from public/favicon.ico rename to web/app/public/favicon.ico diff --git a/public/index.html b/web/app/public/index.html similarity index 100% rename from public/index.html rename to web/app/public/index.html diff --git a/public/logo192.png b/web/app/public/logo192.png similarity index 100% rename from public/logo192.png rename to web/app/public/logo192.png diff --git a/public/logo512.png b/web/app/public/logo512.png similarity index 100% rename from public/logo512.png rename to web/app/public/logo512.png diff --git a/public/manifest.json b/web/app/public/manifest.json similarity index 100% rename from public/manifest.json rename to web/app/public/manifest.json diff --git a/public/robots.txt b/web/app/public/robots.txt similarity index 100% rename from public/robots.txt rename to web/app/public/robots.txt diff --git a/src/App.css b/web/app/src/App.css similarity index 100% rename from src/App.css rename to web/app/src/App.css diff --git a/src/App.test.tsx b/web/app/src/App.test.tsx similarity index 100% rename from src/App.test.tsx rename to web/app/src/App.test.tsx diff --git a/src/App.tsx b/web/app/src/App.tsx similarity index 58% rename from src/App.tsx rename to web/app/src/App.tsx index 8cc4a03..4ae4d66 100644 --- a/src/App.tsx +++ b/web/app/src/App.tsx @@ -1,8 +1,9 @@ import React, { useEffect, useState } from 'react'; -import logo from './logo.svg'; -import apiUrl from './helpers/apiUrl'; +import {ReactComponent as Logo} from './logo.svg'; import './App.css'; -import axios from 'axios'; +import {Api} from "./api"; + +const api = new Api(); function App() { const [helloResponse, setHelloResponse] = useState({}); @@ -12,21 +13,15 @@ function App() { }) function getHello() { - axios - .get(apiUrl("/api/hello"), { - headers: { - Accept: "application/json", - }, + api.api().helloGet().then((response) => { + setHelloResponse(response.data.message) }) - .then((response) => { - setHelloResponse(response.data) - }); } return (
- logo + /api/hello returned: diff --git a/web/app/src/api/api.ts b/web/app/src/api/api.ts new file mode 100644 index 0000000..42e9609 --- /dev/null +++ b/web/app/src/api/api.ts @@ -0,0 +1,14 @@ +import {Configuration, DefaultApi} from "./generated"; + +export class Api { + private configuration(): Configuration { + const openapiConfig = new Configuration(); + if (process.env.REACT_APP_API_HOST !== "") + openapiConfig.basePath = process.env.REACT_APP_API_HOST + return openapiConfig; + }; + + public api(): DefaultApi { + return new DefaultApi(this.configuration()); + }; +} diff --git a/web/app/src/api/index.ts b/web/app/src/api/index.ts new file mode 100644 index 0000000..3318fdb --- /dev/null +++ b/web/app/src/api/index.ts @@ -0,0 +1 @@ +export * from './api' diff --git a/src/index.css b/web/app/src/index.css similarity index 100% rename from src/index.css rename to web/app/src/index.css diff --git a/src/index.tsx b/web/app/src/index.tsx similarity index 100% rename from src/index.tsx rename to web/app/src/index.tsx diff --git a/src/logo.svg b/web/app/src/logo.svg similarity index 100% rename from src/logo.svg rename to web/app/src/logo.svg diff --git a/src/react-app-env.d.ts b/web/app/src/react-app-env.d.ts similarity index 100% rename from src/react-app-env.d.ts rename to web/app/src/react-app-env.d.ts diff --git a/src/reportWebVitals.ts b/web/app/src/reportWebVitals.ts similarity index 86% rename from src/reportWebVitals.ts rename to web/app/src/reportWebVitals.ts index 49a2a16..cfad7f0 100644 --- a/src/reportWebVitals.ts +++ b/web/app/src/reportWebVitals.ts @@ -1,7 +1,7 @@ import { ReportHandler } from 'web-vitals'; const reportWebVitals = (onPerfEntry?: ReportHandler) => { - if (onPerfEntry && onPerfEntry instanceof Function) { + if (onPerfEntry) { import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { getCLS(onPerfEntry); getFID(onPerfEntry); diff --git a/src/setupTests.ts b/web/app/src/setupTests.ts similarity index 100% rename from src/setupTests.ts rename to web/app/src/setupTests.ts diff --git a/tsconfig.json b/web/app/tsconfig.json similarity index 100% rename from tsconfig.json rename to web/app/tsconfig.json diff --git a/yarn.lock b/web/app/yarn.lock similarity index 99% rename from yarn.lock rename to web/app/yarn.lock index 4e7b28f..d7fb27a 100644 --- a/yarn.lock +++ b/web/app/yarn.lock @@ -5699,6 +5699,13 @@ jest-snapshot@^27.5.1: pretty-format "^27.5.1" semver "^7.3.2" +jest-sonar-reporter@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/jest-sonar-reporter/-/jest-sonar-reporter-2.0.0.tgz#faa54a7d2af7198767ee246a82b78c576789cf08" + integrity sha512-ZervDCgEX5gdUbdtWsjdipLN3bKJwpxbvhkYNXTAYvAckCihobSLr9OT/IuyNIRT1EZMDDwR6DroWtrq+IL64w== + dependencies: + xml "^1.0.1" + jest-util@^27.5.1: version "27.5.1" resolved "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz" @@ -9157,6 +9164,11 @@ xml-name-validator@^3.0.0: resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +xml@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== + xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" diff --git a/web/server.go b/web/server.go deleted file mode 100644 index 8c9bc69..0000000 --- a/web/server.go +++ /dev/null @@ -1,82 +0,0 @@ -package web - -import ( - "go-react-app/web/api/health" - "go-react-app/web/api/hello" - - "github.com/gin-contrib/logger" - "github.com/gin-contrib/static" - "github.com/gin-gonic/gin" - "github.com/rs/zerolog" - "github.com/rs/zerolog/log" - ginprometheus "github.com/zsais/go-gin-prometheus" -) - -type Server struct { - SPAPath string - Health *health.Health - Hello *hello.Hello -} - -func NewServer(spaPath string) *Server { - return &Server{ - SPAPath: spaPath, - Health: health.NewHealth(), - Hello: hello.NewHello(), - } -} - -func (s *Server) StartServer() { - router := gin.New() - - zerolog.SetGlobalLevel(zerolog.InfoLevel) - if gin.IsDebugging() { - zerolog.SetGlobalLevel(zerolog.DebugLevel) - } - - router.Use(logger.SetLogger(logger.Config{ - SkipPath: []string{ - "/health", - "/metrics", - }, - })) - - prometheus := ginprometheus.NewPrometheus("gin") - - // Prevents high cardinality of metrics Source: https://github.com/zsais/go-gin-prometheus#preserving-a-low-cardinality-for-the-request-counter - prometheus.ReqCntURLLabelMappingFn = func(c *gin.Context) string { - url := c.Request.URL.Path // Query params are dropped here so there is not a metric for every permutation of query param usage on a route - - // If a route uses parameters, replace the parameter value with its name. Else there will be a metric for the route with - // with every possible value of that parameter and this will cause performance issues in Prometheus. - // - // If your service uses route parameters, uncomment the for loop below and add a case for each parameter. The example case - // below works for routes with a parameter called 'name', like '/api/function/:name' - // -- - // for _, p := range c.Params { - // switch p.Key { - // case "name": - // url = strings.Replace(url, p.Value, ":name", 1) - // } - // } - return url - } - prometheus.Use(router) - - router.Use(errorHandler) - - // API ROUTES - router.GET("/api/health", s.Health.Get) - router.GET("/api/hello", s.Hello.Get) - - // SPA ROUTE - // Only loaded if SPAPath is defined. - if s.SPAPath != "" { - router.Use(static.Serve("/", static.LocalFile(s.SPAPath, true))) - } - - err := router.Run() - if err != nil { - log.Error().Msgf("Web server startup failed with error %s", err) - } -}