diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e5c60ab --- /dev/null +++ b/.dockerignore @@ -0,0 +1,32 @@ +# Include any files or directories that you don't want to be copied to your +# container here (e.g., local build artifacts, temporary files, etc.). +# +# For more help, visit the .dockerignore file reference guide at +# https://docs.docker.com/go/build-context-dockerignore/ + +**/.DS_Store +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/bin +**/charts +**/docker-compose* +**/compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md diff --git a/.github/workflows/release-staging.yml b/.github/workflows/release-staging.yml new file mode 100644 index 0000000..c4da81a --- /dev/null +++ b/.github/workflows/release-staging.yml @@ -0,0 +1,67 @@ +name: Deploy to Staging + +on: + workflow_dispatch: + push: + branches: + - develop + - yash/group + +jobs: + deploy: + name: Deploy + runs-on: ubuntu-latest + environment: staging + + env: + AWS_REGION: ${{ vars.AWS_REGION }} + ECR_REPOSITORY: ${{ vars.ECR_REPOSITORY }} + ECS_SERVICE: ${{ vars.ECS_SERVICE }} + ECS_CLUSTER: ${{ vars.ECS_CLUSTER }} + ECS_TASK_DEFINITION: ${{ vars.ECS_TASK_DEFINITION }} + CONTAINER_NAME: ${{ vars.CONTAINER_NAME }} + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ env.AWS_REGION }} + + - name: Download task definition + run: | + aws ecs describe-task-definition --task-definition wisee-backend --query taskDefinition > task-definition.json + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + - name: Build + id: build-image + env: + ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} + IMAGE_TAG: ${{ github.sha }} + run: | + docker build -f docker/release.dockerfile -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . + docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG + echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" + + - name: Fill in the new image ID in the Amazon ECS task definition + id: task-def + uses: aws-actions/amazon-ecs-render-task-definition@v1 + with: + task-definition: ${{ env.ECS_TASK_DEFINITION }} + container-name: ${{ env.CONTAINER_NAME }} + image: ${{ steps.build-image.outputs.image }} + + - name: Deploy Amazon ECS task definition + uses: aws-actions/amazon-ecs-deploy-task-definition@v1 + with: + task-definition: ${{ steps.task-def.outputs.task-definition }} + service: ${{ env.ECS_SERVICE }} + cluster: ${{ env.ECS_CLUSTER }} + wait-for-service-stability: false diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c850d42..fcdf47a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,12 +1,27 @@ -name: Test +name: Tests on: pull_request: branches: ["*"] jobs: - unit-tests: + tests: runs-on: ubuntu-latest + + services: + postgres: + image: postgres:latest + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: wisee_core_test + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 name: Run tests steps: @@ -23,7 +38,10 @@ jobs: - run: go version - name: Copy Env - run: cp ./environments/dev.env .env + run: cp ./environments/test.env .env - name: Run Unit tests - run: go test ./tests/unit + run: make test_unit + + - name: Run Integration tests + run: make test_integration diff --git a/Makefile b/Makefile index 18deb84..aeb2520 100644 --- a/Makefile +++ b/Makefile @@ -16,15 +16,23 @@ ifeq ($(ARCH),x86_64) ARCH := amd64 else ifeq ($(ARCH),i386) ARCH := 386 +else ifeq ($(ARCH),aarch64) + ARCH := arm64 endif build: @echo "Building $(OS) $(ARCH) binary..." - @GOOS=$(OS) GOARCH=$(ARCH) go build $(ARGS) -o "bin/$(BINARY_NAME)" src/main.go + @GOOS=$(OS) GOARCH=$(ARCH) CGO_ENABLED=0 go build $(ARGS) -o "bin/$(BINARY_NAME)" ./src -test: +test_unit: @echo "Running tests..." - @@GOOS=$(OS) GOARCH=$(ARCH) ENV=test go test -race -covermode=atomic -v -coverpkg=./src/... ./tests/... ./src/... + @@GOOS=$(OS) GOARCH=$(ARCH) ENV=test go test -race -covermode=atomic -v -coverpkg=./src/... ./tests/unit/... ./src/... + +test_integration: + @echo "Running tests..." + @@GOOS=$(OS) GOARCH=$(ARCH) ENV=test go test -race -covermode=atomic -v -coverpkg=./src/... ./tests/integration/... ./src/... + +test: test_unit test_integration clean: @echo "Cleaning..." @@ -51,7 +59,7 @@ watch: # Up all migrations migrate-all-up: @if command -v migrate > /dev/null; then \ - migrate -path ./migrations -database $(DEV_DATABASE_URL) -path ./database/migrations up; \ + migrate -database $(DEV_DATABASE_URL) -path ./database/migrations up; \ else \ echo "Golang Migrate cli is not installed on your machine. Exiting..."; \ exit 1; \ @@ -60,7 +68,7 @@ migrate-all-up: # Drop all migrations when in development migrate-all-down: @if command -v migrate > /dev/null; then \ - migrate -path ./migrations -database $(DEV_DATABASE_URL) -path ./database/migrations down; \ + migrate -database $(DEV_DATABASE_URL) -path ./database/migrations down; \ else \ echo "Golang Migrate cli is not installed on your machine. Exiting..."; \ exit 1; \ diff --git a/docker/release.dockerfile b/docker/release.dockerfile new file mode 100644 index 0000000..f1fb4ac --- /dev/null +++ b/docker/release.dockerfile @@ -0,0 +1,57 @@ +# Create a stage for building the application. +ARG GO_VERSION=1.21.0 +FROM golang:${GO_VERSION} AS build +WORKDIR /src + +# Download dependencies as a separate step to take advantage of Docker's caching. +RUN --mount=type=cache,target=/go/pkg/mod/ \ + --mount=type=bind,source=go.sum,target=go.sum \ + --mount=type=bind,source=go.mod,target=go.mod \ + go mod download -x + +# This is the architecture you’re building for, which is passed in by the builder. +# Placing it here allows the previous steps to be cached across architectures. +ARG TARGETARCH + +# Build the application. +# Leverage a cache mount to /go/pkg/mod/ to speed up subsequent builds. +# Leverage a bind mount to the current directory to avoid having to copy the +# source code into the container. +RUN --mount=type=cache,target=/go/pkg/mod/ \ + --mount=type=bind,target=. \ + GOOS=linux CGO_ENABLED=0 GOARCH=amd64 go build -o /bin/server ./src + +################################################################################ +# Create a new stage for running the application that contains the minimal +FROM alpine:latest AS final + +# Install any runtime dependencies that are needed to run your application. +# Leverage a cache mount to /var/cache/apk/ to speed up subsequent builds. +RUN --mount=type=cache,target=/var/cache/apk \ + apk --update add \ + ca-certificates \ + tzdata \ + && \ + update-ca-certificates + +# Create a non-privileged user that the app will run under. +# See https://docs.docker.com/go/dockerfile-user-best-practices/ +ARG UID=10001 +RUN adduser \ + --disabled-password \ + --gecos "" \ + --home "/nonexistent" \ + --shell "/sbin/nologin" \ + --no-create-home \ + --uid "${UID}" \ + appuser +USER appuser + +# Copy the executable from the "build" stage. +COPY --from=build /bin/server /bin/ + +# Expose port 8080 to the outside world +EXPOSE 8080 + +# Command to run the executable +ENTRYPOINT [ "/bin/server" ] diff --git a/environments/dev.env b/environments/dev.env index b960f7d..5efa24d 100644 --- a/environments/dev.env +++ b/environments/dev.env @@ -1,5 +1,6 @@ +ENV="dev" JWT_SECRET="secret" -JWT_VALIDITY_IN_HOURS=24 +JWT_VALIDITY_IN_DAYS=1 JWT_ISSUER="wisee-backend" DOMAIN="localhost" diff --git a/environments/test.env b/environments/test.env new file mode 100644 index 0000000..6454b08 --- /dev/null +++ b/environments/test.env @@ -0,0 +1,15 @@ +ENV="test" +JWT_SECRET="secret" +JWT_VALIDITY_IN_DAYS=1 +JWT_ISSUER="wisee-backend" + +DOMAIN="localhost" +AUTH_REDIRECT_URL="http://localhost:3000/dashboard" + +DB_URL="postgresql://postgres:postgres@localhost:5432/wisee_core?sslmode=disable" +TEST_DB_URL="postgresql://postgres:postgres@localhost:5432/wisee_core_test?sslmode=disable" +DB_MAX_OPEN_CONNECTIONS=10 + +GOOGLE_CLIENT_ID="google-client-id" +GOOGLE_CLIENT_SECRET="google-client-secret" +GOOGLE_REDIRECT_URL="http://localhost:8080/v1/auth/google/callback" diff --git a/go.mod b/go.mod index 9e65317..bf8de80 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/gin-gonic/gin v1.9.1 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/joho/godotenv v1.5.1 + github.com/lib/pq v1.10.9 github.com/uptrace/bun v1.1.14 github.com/uptrace/bun/dialect/pgdialect v1.1.14 github.com/uptrace/bun/driver/pgdriver v1.1.14 @@ -16,11 +17,8 @@ require ( ) require ( - github.com/google/go-github/v39 v39.2.0 // indirect - github.com/google/go-querystring v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/lib/pq v1.10.9 // indirect go.uber.org/atomic v1.7.0 // indirect ) @@ -55,7 +53,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.9 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/testify v1.8.4 // indirect + github.com/stretchr/testify v1.8.4 github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect diff --git a/go.sum b/go.sum index ee5941d..9fa0285 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,13 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= -cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk= @@ -25,6 +25,16 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 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/dhui/dktest v0.4.0 h1:z05UmuXZHO/bgj/ds2bGMBu8FI4WA+Ag/m3ghL+om7M= +github.com/dhui/dktest v0.4.0/go.mod h1:v/Dbz1LgCBOi2Uki2nUqLBGa83hWBGFMu5MrgMDCc78= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= +github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -41,6 +51,8 @@ github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR 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-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +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.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= 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= @@ -53,6 +65,8 @@ github.com/go-playground/validator/v10 v10.15.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QX github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 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/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-migrate/migrate/v4 v4.17.0 h1:rd40H3QXU0AA4IoLllFcEAEo9dYKRHYND2gB4p7xcaU= @@ -80,24 +94,16 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/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.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-github/v39 v39.2.0 h1:rNNM311XtPOz5rDdsJXAp2o8F67X9FnROXTvto3aSnQ= -github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +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/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= -github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= @@ -119,9 +125,11 @@ github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +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.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= @@ -134,19 +142,30 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= 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 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -190,17 +209,14 @@ golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -209,20 +225,16 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -234,10 +246,6 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/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.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -245,10 +253,6 @@ 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.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -256,9 +260,9 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= +golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.142.0 h1:mf+7EJ94fi5ZcnpPy+m0Yv2dkz8bKm+UL0snTCuwXlY= -google.golang.org/api v0.142.0/go.mod h1:zJAN5o6HRqR7O+9qJUFOWrZkYE66RH+efPBdTLA4xBA= google.golang.org/api v0.150.0 h1:Z9k22qD289SZ8gCJrk4DrWXkNjtfvKAUo/l1ma8eBYE= google.golang.org/api v0.150.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -268,9 +272,10 @@ google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb h1:Isk1sSH7bovx8Rti2wZK0UZF6oraBDK74uoyLEEVFN0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik= google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -278,8 +283,6 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -298,6 +301,7 @@ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/src/config/core-config.go b/src/config/core-config.go new file mode 100644 index 0000000..8fd03bc --- /dev/null +++ b/src/config/core-config.go @@ -0,0 +1,87 @@ +package config + +import ( + "os" + "path" + "runtime" + "strconv" + + "github.com/Real-Dev-Squad/wisee-backend/src/utils/logger" + "github.com/joho/godotenv" +) + +var Env string + +var JwtSecret string +var JwtValidityInDays int +var JwtIssuer string + +var Domain string +var AuthRedirectUrl string + +var DbUrl string +var TestDbUrl string +var DbMaxOpenConnections int + +var GoogleClientId string +var GoogleClientSecret string +var GoogleRedirectUrl string + +func loadEnv() { + env := os.Getenv("ENV") + + // If the environment is production, we don't need to load the .env file + // we assume that the environment variables are already set + if env == "production" || env == "staging" { + return + } + + if env == "test" { + // for tests, chdir to the project root + _, filename, _, _ := runtime.Caller(0) + dir := path.Join(path.Dir(filename), "../..") + + if err := os.Chdir(dir); err != nil { + panic(err) + } + + if err := godotenv.Load(".env"); err != nil { + logger.Error("Error loading .env file.", err) + } + + return + } + + if err := godotenv.Load(".env"); err != nil { + logger.Fatal("Error loading .env file") + } +} + +func init() { + loadEnv() + + env := os.Getenv("ENV") + + if env == "" { + Env = "dev" + } else { + Env = env + } + + JwtSecret = os.Getenv("JWT_SECRET") + JwtValidityInDays, _ = strconv.Atoi(os.Getenv("JWT_VALIDITY_IN_DAYS")) + JwtIssuer = os.Getenv("JWT_ISSUER") + + Domain = os.Getenv("DOMAIN") + AuthRedirectUrl = os.Getenv("AUTH_REDIRECT_URL") + + DbUrl = os.Getenv("DB_URL") + TestDbUrl = os.Getenv("TEST_DB_URL") + DbMaxOpenConnections, _ = strconv.Atoi(os.Getenv("DB_MAX_OPEN_CONNECTIONS")) + + GoogleClientId = os.Getenv("GOOGLE_CLIENT_ID") + GoogleClientSecret = os.Getenv("GOOGLE_CLIENT_SECRET") + GoogleRedirectUrl = os.Getenv("GOOGLE_REDIRECT_URL") + + logger.Info("Loaded environment variables") +} diff --git a/src/main.go b/src/main.go index eee6f4d..c0b189e 100644 --- a/src/main.go +++ b/src/main.go @@ -2,19 +2,18 @@ package main import ( "flag" - "os" + "github.com/Real-Dev-Squad/wisee-backend/src/config" "github.com/Real-Dev-Squad/wisee-backend/src/routes" "github.com/Real-Dev-Squad/wisee-backend/src/utils" ) func main() { - utils.LoadEnv(".env") - dsn := os.Getenv("DB_URL") - db := utils.SetupDBConnection(dsn) + dsn := config.DbUrl + _, bunDbInstance := utils.SetupDBConnection(dsn) port := flag.String("port", ":8080", "server address to listen on") flag.Parse() - routes.Listen("127.0.0.1"+*port, db) + routes.Listen("0.0.0.0"+*port, bunDbInstance) } diff --git a/src/routes/auth.go b/src/routes/auth.go index ac9f54e..3964ae9 100644 --- a/src/routes/auth.go +++ b/src/routes/auth.go @@ -2,12 +2,11 @@ package routes import ( "context" - "fmt" - "log" - "os" + "github.com/Real-Dev-Squad/wisee-backend/src/config" "github.com/Real-Dev-Squad/wisee-backend/src/models" "github.com/Real-Dev-Squad/wisee-backend/src/utils" + "github.com/Real-Dev-Squad/wisee-backend/src/utils/logger" "github.com/gin-gonic/gin" "github.com/uptrace/bun" "golang.org/x/oauth2" @@ -43,9 +42,10 @@ func AuthRoutes(reg *gin.RouterGroup, db *bun.DB) { googleAuth := auth.Group("/google") conf := &oauth2.Config{ - ClientID: os.Getenv("GOOGLE_CLIENT_ID"), - ClientSecret: os.Getenv("GOOGLE_CLIENT_SECRET"), - RedirectURL: os.Getenv("GOOGLE_REDIRECT_URL"), + ClientID: config.GoogleClientId, + ClientSecret: config.GoogleClientSecret, + RedirectURL: config.GoogleRedirectUrl, + Scopes: []string{ "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", @@ -55,21 +55,19 @@ func AuthRoutes(reg *gin.RouterGroup, db *bun.DB) { googleAuth.GET("/login", func(ctx *gin.Context) { url := conf.AuthCodeURL("state") - fmt.Printf("Visit the URL for the auth dialog: %v", url) - ctx.Redirect(302, url) }) googleAuth.GET(("/callback"), func(ctx *gin.Context) { code := ctx.Query("code") - domain := os.Getenv("DOMAIN") - authRedirectUrl := os.Getenv("AUTH_REDIRECT_URL") + domain := config.Domain + authRedirectUrl := config.AuthRedirectUrl user := new(models.User) googleAccountInfo, getInfoError := getUserInfoFromCode(code, conf, ctx) if getInfoError != nil { - log.Fatal(getInfoError) + logger.Fatal(getInfoError) ctx.JSON(500, gin.H{ "message": "error", }) @@ -87,17 +85,19 @@ func AuthRoutes(reg *gin.RouterGroup, db *bun.DB) { _, err := db.NewInsert().Model(newUser).Exec(ctx) if err != nil { - log.Fatal(err) + logger.Fatal(err) ctx.JSON(500, gin.H{ "message": "error", }) } + + user = newUser } token, err := utils.GenerateToken(user) if err != nil { - log.Fatal(err) + logger.Fatal(err) ctx.JSON(500, gin.H{ "message": "error", }) diff --git a/src/routes/health.go b/src/routes/health.go new file mode 100644 index 0000000..6e00394 --- /dev/null +++ b/src/routes/health.go @@ -0,0 +1,30 @@ +package routes + +import ( + "net/http" + + "github.com/Real-Dev-Squad/wisee-backend/src/utils/logger" + "github.com/gin-gonic/gin" + "github.com/uptrace/bun" +) + +func HealthRoutes(rg *gin.RouterGroup, db *bun.DB) { + healthCheck := rg.Group("/health") + + healthCheck.GET("", func(ctx *gin.Context) { + err := db.Ping() + + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{ + "message": "error", + }) + + logger.Error(err) + return + } + + ctx.JSON(http.StatusOK, gin.H{ + "message": "OK", + }) + }) +} diff --git a/src/routes/main.go b/src/routes/main.go index 97d1564..4175f97 100644 --- a/src/routes/main.go +++ b/src/routes/main.go @@ -9,16 +9,14 @@ import ( func SetupV1Routes(db *bun.DB) *gin.Engine { var router = gin.Default() - v1 := router.Group("v1/") + // TODO: Configure CORS properly to allow only access from certain origins + router.Use(cors.Default()) + + v1 := router.Group("wisee/v1/") UserRoutes(v1, db) AuthRoutes(v1, db) FormRoutes(v1, db) - - router.GET("/health", func(ctx *gin.Context) { - ctx.JSON(200, gin.H{ - "message": "OK", - }) - }) + HealthRoutes(v1, db) return router } @@ -26,7 +24,5 @@ func SetupV1Routes(db *bun.DB) *gin.Engine { func Listen(listenAddress string, db *bun.DB) { router := SetupV1Routes(db) - // TODO: Configure CORS properly to allow only access from certain origins - router.Use(cors.Default()) router.Run(listenAddress) } diff --git a/src/utils/db.go b/src/utils/db.go index 0a48f32..939322b 100644 --- a/src/utils/db.go +++ b/src/utils/db.go @@ -2,33 +2,26 @@ package utils import ( "database/sql" - "os" - "strconv" + "github.com/Real-Dev-Squad/wisee-backend/src/config" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/pgdialect" "github.com/uptrace/bun/driver/pgdriver" "github.com/uptrace/bun/extra/bundebug" ) -func SetupDBConnection(dsn string) *bun.DB { - maxOpenConnectionsStr := os.Getenv("DB_MAX_OPEN_CONNECTIONS") - maxOpenConnections, err := strconv.Atoi(maxOpenConnectionsStr) - - if err != nil { - panic(err) - } +func SetupDBConnection(dsn string) (*sql.DB, *bun.DB) { + maxOpenConnections := config.DbMaxOpenConnections pgDB := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn))) - pgDB.SetMaxOpenConns(maxOpenConnections) - db := bun.NewDB(pgDB, pgdialect.New()) + bunDbInstance := bun.NewDB(pgDB, pgdialect.New()) - db.AddQueryHook(bundebug.NewQueryHook( + bunDbInstance.AddQueryHook(bundebug.NewQueryHook( bundebug.WithVerbose(true), bundebug.FromEnv("BUNDEBUG"), )) - return db + return pgDB, bunDbInstance } diff --git a/src/utils/env.go b/src/utils/env.go deleted file mode 100644 index 515b911..0000000 --- a/src/utils/env.go +++ /dev/null @@ -1,15 +0,0 @@ -package utils - -import ( - "log" - - "github.com/joho/godotenv" -) - -func LoadEnv(path string) { - err := godotenv.Load(path) - - if err != nil { - log.Fatalf("Error loading .env file") - } -} diff --git a/src/utils/jwt.go b/src/utils/jwt.go index d7ac40c..e830396 100644 --- a/src/utils/jwt.go +++ b/src/utils/jwt.go @@ -2,33 +2,28 @@ package utils import ( "errors" - "os" - "strconv" "time" + "github.com/Real-Dev-Squad/wisee-backend/src/config" "github.com/Real-Dev-Squad/wisee-backend/src/models" "github.com/golang-jwt/jwt/v5" ) +var jwtSecret = config.JwtSecret +var jwtValidityInDays = config.JwtValidityInDays + /* * GenerateToken generates a JWT token for the user */ func GenerateToken(user *models.User) (string, error) { - issuer := os.Getenv("JWT_ISSUER") - key := []byte(os.Getenv("JWT_SECRET")) - - tokenValidityInHours, err := strconv.ParseInt(os.Getenv("JWT_VALIDITY_IN_HOURS"), 10, 8) - - if err != nil { - return "", err - } - - tokenExpiryTime := time.Now().Add(time.Second * time.Duration(tokenValidityInHours)).UTC().Format(time.RFC3339) + issuer := config.JwtIssuer + key := []byte(jwtSecret) t := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{ "iss": issuer, - "exp": tokenExpiryTime, "email": user.Email, + "iat": jwt.NewNumericDate(time.Now()), + "exp": jwt.NewNumericDate(time.Now().AddDate(0, 0, jwtValidityInDays)), }) token, error := t.SignedString(key) @@ -40,32 +35,36 @@ func GenerateToken(user *models.User) (string, error) { * VerifyToken verifies the token and returns the email of the user */ func VerifyToken(tokenString string) (string, error) { - var claims jwt.MapClaims = nil - - token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { - + token, tokenErr := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { if token.Method.Alg() != jwt.SigningMethodHS512.Alg() { return nil, jwt.ErrSignatureInvalid } - return []byte(os.Getenv("JWT_SECRET")), nil + return []byte(jwtSecret), nil }) - if c, ok := token.Claims.(jwt.MapClaims); !ok && !token.Valid { - return "", err - } else { - claims = c + if tokenErr != nil || !token.Valid { + return "", tokenErr } - expiryTime, err := time.Parse(time.RFC3339, claims["exp"].(string)) + claims, ok := token.Claims.(jwt.MapClaims) + if !ok { + return "", errors.New("token claims are not in expected format") + } + exp, err := claims.GetExpirationTime() if err != nil { return "", err } - if time.Now().UTC().After(expiryTime) { + if exp.Before(time.Now().UTC()) { return "", errors.New("token has expired") } - return claims["email"].(string), nil + email, ok := claims["email"].(string) + if !ok { + return "", errors.New("email not found in token") + } + + return email, nil } diff --git a/src/utils/logger/logger.go b/src/utils/logger/logger.go new file mode 100644 index 0000000..9a6c9fb --- /dev/null +++ b/src/utils/logger/logger.go @@ -0,0 +1,70 @@ +// inspired by: https://github.com/championswimmer/onepixel_backend/blob/1ed767e2244832bf8e50be1eaa3d4f2edb7e1190/src/utils/applogger/app_logger.go + +package logger + +import ( + "log" + "os" + "runtime" +) + +const ( + _reset = "\033[0m" + _red = "\033[31m" + _green = "\033[32m" + _yellow = "\033[33m" + _blue = "\033[34m" + _magenta = "\033[35m" + _cyan = "\033[36m" + _white = "\033[37m" + _redbold = "\033[31;1m" + _greenbold = "\033[32;1m" + _yellowbold = "\033[33;1m" + _bluebold = "\033[34;1m" + _magentabold = "\033[35;1m" + _cyanbold = "\033[36;1m" +) + +var logFlags = log.LstdFlags | log.LUTC | log.Lmsgprefix | log.Lshortfile +var ( + traceLogger = log.New(os.Stdout, _cyanbold+"[TRACE] "+_reset, logFlags) + debugLogger = log.New(os.Stdout, _bluebold+"[DEBUG] "+_reset, logFlags) + infoLogger = log.New(os.Stdout, _greenbold+"[INFO] "+_reset, logFlags) + warnLogger = log.New(os.Stdout, _yellowbold+"[WARN] "+_reset, logFlags) + errorLogger = log.New(os.Stderr, _redbold+"[ERROR] "+_reset, logFlags) + fatalLogger = log.New(os.Stderr, _magentabold+"[FATAL] "+_reset, logFlags) + panicLogger = log.New(os.Stderr, _magentabold+"[PANIC] "+_reset, logFlags) +) + +func Trace(v ...interface{}) { + traceLogger.Println(v...) +} + +func Debug(v ...interface{}) { + debugLogger.Println(v...) +} + +func Info(v ...interface{}) { + infoLogger.Println(v...) + +} + +func Warn(v ...interface{}) { + warnLogger.Println(v...) + +} + +func Error(v ...interface{}) { + errorLogger.Println(v...) +} + +func Fatal(v ...interface{}) { + _, file, line, _ := runtime.Caller(1) + fatalLogger.Printf("%s:%d: %v\n", file, line, v) + os.Exit(1) +} + +func Panic(v ...interface{}) { + panicLogger.Println(v...) + panic(v) +} diff --git a/tests/integration/form_test.go b/tests/integration/form_test.go index df7f483..1416fd2 100644 --- a/tests/integration/form_test.go +++ b/tests/integration/form_test.go @@ -29,7 +29,7 @@ func TestFormCreation(t *testing.T) { jsonValue, _ := json.Marshal(requestBody) w := httptest.NewRecorder() - req, err := http.NewRequest("POST", "/v1/forms", bytes.NewBuffer(jsonValue)) + req, err := http.NewRequest("POST", "/wisee/v1/forms", bytes.NewBuffer(jsonValue)) router.ServeHTTP(w, req) @@ -70,7 +70,7 @@ func TestFormCreationNoPerformedById(t *testing.T) { jsonValue, _ := json.Marshal(requestBody) w := httptest.NewRecorder() - req, err := http.NewRequest("POST", "/v1/forms", bytes.NewBuffer(jsonValue)) + req, err := http.NewRequest("POST", "/wisee/v1/forms", bytes.NewBuffer(jsonValue)) router.ServeHTTP(w, req) @@ -95,7 +95,7 @@ func TestFormCreationNoPerformedById(t *testing.T) { func TestFormGetAll(t *testing.T) { router := routes.SetupV1Routes(db) w := httptest.NewRecorder() - req, err := http.NewRequest("GET", "/v1/forms", nil) + req, err := http.NewRequest("GET", "/wisee/v1/forms", nil) router.ServeHTTP(w, req) @@ -121,7 +121,7 @@ func TestFormGetAll(t *testing.T) { func TestFormGetById(t *testing.T) { router := routes.SetupV1Routes(db) w := httptest.NewRecorder() - req, err := http.NewRequest("GET", fmt.Sprintf("/v1/forms/%v", form.Id), nil) + req, err := http.NewRequest("GET", fmt.Sprintf("/wisee/v1/forms/%v", form.Id), nil) router.ServeHTTP(w, req) if err != nil { @@ -150,7 +150,7 @@ func TestFormGetById(t *testing.T) { func TestFormGetByInvalidId(t *testing.T) { router := routes.SetupV1Routes(db) w := httptest.NewRecorder() - req, err := http.NewRequest("GET", fmt.Sprintf("/v1/forms/%v", 1526), nil) + req, err := http.NewRequest("GET", fmt.Sprintf("/wisee/v1/forms/%v", 1526), nil) router.ServeHTTP(w, req) if err != nil { @@ -187,7 +187,7 @@ func TestFormUpdate(t *testing.T) { jsonValue, _ := json.Marshal(requestBody) w := httptest.NewRecorder() - req, err := http.NewRequest("PATCH", fmt.Sprintf("/v1/forms/%v", form.Id), bytes.NewBuffer(jsonValue)) + req, err := http.NewRequest("PATCH", fmt.Sprintf("/wisee/v1/forms/%v", form.Id), bytes.NewBuffer(jsonValue)) router.ServeHTTP(w, req) if err != nil { @@ -223,7 +223,7 @@ func TestFormUpdateInavlidStatus(t *testing.T) { jsonValue, _ := json.Marshal(requestBody) w := httptest.NewRecorder() - req, err := http.NewRequest("PATCH", fmt.Sprintf("/v1/forms/%v", form.Id), bytes.NewBuffer(jsonValue)) + req, err := http.NewRequest("PATCH", fmt.Sprintf("/wisee/v1/forms/%v", form.Id), bytes.NewBuffer(jsonValue)) router.ServeHTTP(w, req) if err != nil { @@ -252,7 +252,7 @@ func TestFormUpdateInavlidFormId(t *testing.T) { jsonValue, _ := json.Marshal(requestBody) w := httptest.NewRecorder() - req, err := http.NewRequest("PATCH", fmt.Sprintf("/v1/forms/%v", 15668), bytes.NewBuffer(jsonValue)) + req, err := http.NewRequest("PATCH", fmt.Sprintf("/wisee/v1/forms/%v", 15668), bytes.NewBuffer(jsonValue)) router.ServeHTTP(w, req) if err != nil { diff --git a/tests/integration/main_test.go b/tests/integration/main_test.go index 907d876..847dd1c 100644 --- a/tests/integration/main_test.go +++ b/tests/integration/main_test.go @@ -1,38 +1,53 @@ package integration_tests import ( - "fmt" - "os" - "os/exec" "testing" + _ "github.com/lib/pq" + + "github.com/Real-Dev-Squad/wisee-backend/src/config" "github.com/Real-Dev-Squad/wisee-backend/src/utils" + "github.com/Real-Dev-Squad/wisee-backend/src/utils/logger" "github.com/uptrace/bun" + + "github.com/golang-migrate/migrate/v4" + "github.com/golang-migrate/migrate/v4/database/postgres" + _ "github.com/golang-migrate/migrate/v4/source/file" ) var db *bun.DB func TestMain(m *testing.M) { - utils.LoadEnv("../../.env") - dsn := os.Getenv("TEST_DB_URL") - db = utils.SetupDBConnection(dsn) - defer TeardownDb(dsn) - - migration_cmd := exec.Command("migrate", "-path", "../../database/migrations", "-database", dsn, "up") // run migrations - // Execute the migrations - _, err := migration_cmd.Output() + dsn := config.TestDbUrl + db, bunDb := utils.SetupDBConnection(dsn) + defer bunDb.Close() + + // use the db connection from the `setupDBConnection` function to run migrations + driver, pgInstanceErr := postgres.WithInstance(db, &postgres.Config{}) + + if pgInstanceErr != nil { + logger.Fatal("pg instance error: ", pgInstanceErr) + } + + migration, err := migrate.NewWithDatabaseInstance( + "file://database/migrations", // "file://" + path of the migrations folder (not using "file://" will throw an error) + "postgres", driver) + if err != nil { - fmt.Println("Error executing migration up command:", err) - return + logger.Fatal("migrate: database instance error: ", err) } - defer db.Close() - // setup fixtures - if err := SetupFixtures(db); err != nil { - fmt.Println("Error setting up fixtures:", err) - return + if err := migration.Up(); err != nil { + logger.Fatal("migration error: ", err) } - code := m.Run() - os.Exit(code) + logger.Info("Migrations complete") + + // teardown the database after the tests + defer TeardownDb(migration) + + // setup fixtures + if err := SetupFixtures(bunDb); err != nil { + logger.Fatal("Error setting up fixtures:", err) + } } diff --git a/tests/integration/users_test.go b/tests/integration/users_test.go index 06a5489..4486586 100644 --- a/tests/integration/users_test.go +++ b/tests/integration/users_test.go @@ -12,7 +12,7 @@ func TestGetUsers(t *testing.T) { router := routes.SetupV1Routes(db) w := httptest.NewRecorder() - req, err := http.NewRequest("GET", "/v1/users", nil) + req, err := http.NewRequest("GET", "/wisee/v1/users", nil) router.ServeHTTP(w, req) diff --git a/tests/integration/utils_test.go b/tests/integration/utils_test.go index fa1ff58..6a89ad4 100644 --- a/tests/integration/utils_test.go +++ b/tests/integration/utils_test.go @@ -3,12 +3,11 @@ package integration_tests import ( "context" "encoding/json" - "fmt" - "log" - "os/exec" "github.com/Real-Dev-Squad/wisee-backend/src/dtos" "github.com/Real-Dev-Squad/wisee-backend/src/models" + "github.com/Real-Dev-Squad/wisee-backend/src/utils/logger" + "github.com/golang-migrate/migrate/v4" "github.com/uptrace/bun" ) @@ -24,6 +23,8 @@ type TestResponseDto struct { func SetupFixtures(db *bun.DB) error { var ctx = context.Background() + logger.Info("setting up fixtures") + defer logger.Info("fixtures setup complete") userFixture := &models.User{Username: "test_user", Email: "test_user@admin.com", Password: "password"} if _, err := db.NewInsert().Model(userFixture).Exec(ctx); err != nil { @@ -48,13 +49,11 @@ func SetupFixtures(db *bun.DB) error { return nil } -func TeardownDb(dsn string) { - migration_down_cmd := exec.Command("migrate", "-path", "../../database/migrations", "-database", dsn, "down", "-all") // down the - // Execute the migrations - _, err := migration_down_cmd.Output() - if err != nil { - log.Fatal("Error executing migration down command:", err) - fmt.Println("You may have to manually teardown the database") - return +func TeardownDb(migrate *migrate.Migrate) { + logger.Info("Running migration down") + defer logger.Info("Migration down complete") + + if err := migrate.Down(); err != nil { + logger.Fatal("failed to run migration down: ", err) } } diff --git a/tests/unit/jwt_test.go b/tests/unit/jwt_test.go index 91e8eed..648c203 100644 --- a/tests/unit/jwt_test.go +++ b/tests/unit/jwt_test.go @@ -4,14 +4,15 @@ import ( "os" "testing" + "github.com/Real-Dev-Squad/wisee-backend/src/config" "github.com/Real-Dev-Squad/wisee-backend/src/models" "github.com/Real-Dev-Squad/wisee-backend/src/utils" + "github.com/Real-Dev-Squad/wisee-backend/src/utils/logger" ) func TestMain(m *testing.M) { - utils.LoadEnv("../../.env") - code := m.Run() + logger.Info(config.JwtValidityInDays) os.Exit(code) }