diff --git a/.circleci/config.yml b/.circleci/config.yml index 272c765024..e3f186eaf5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,7 +9,7 @@ jobs: # that flag starts the download asynchronously so we'd have a race # condition. # renovate: datasource=github-releases depName=hashicorp/terraform versioning=hashicorp - TERRAFORM_VERSION: 1.5.5 + TERRAFORM_VERSION: 1.5.7 steps: - checkout - run: make build-service diff --git a/.github/workflows/atlantis-image.yml b/.github/workflows/atlantis-image.yml index a0f33cfd1f..08bb3a94e2 100644 --- a/.github/workflows/atlantis-image.yml +++ b/.github/workflows/atlantis-image.yml @@ -33,7 +33,7 @@ jobs: PUSH: ${{ github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # Lint the Dockerfile first before setting anything up - name: Lint Dockerfile @@ -94,7 +94,7 @@ jobs: # Suffix is not used here since there's no way to disable it above - name: Login to Packages Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} @@ -107,7 +107,7 @@ jobs: - name: "Build ${{ env.PUSH == 'true' && 'and push' || '' }} ${{ env.DOCKER_REPO }} image" if: contains(fromJson('["push", "pull_request"]'), github.event_name) - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: cache-from: type=gha cache-to: type=gha,mode=max diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index c2e8665e55..57eb362445 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -53,7 +53,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8f35fba1d3..2b39dec606 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -25,7 +25,7 @@ jobs: name: runner / golangci-lint runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: golangci-lint uses: reviewdog/action-golangci-lint@v2 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1e4d8a57a2..056e366757 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: true diff --git a/.github/workflows/renovate-config.yml b/.github/workflows/renovate-config.yml index 945bb6592e..4e25c9875c 100644 --- a/.github/workflows/renovate-config.yml +++ b/.github/workflows/renovate-config.yml @@ -15,6 +15,6 @@ jobs: validate: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-node@v3 - run: npx --package renovate -c 'renovate-config-validator' diff --git a/.github/workflows/test-required.yml b/.github/workflows/test-required.yml deleted file mode 100644 index 7ef2984b6b..0000000000 --- a/.github/workflows/test-required.yml +++ /dev/null @@ -1,37 +0,0 @@ -# For required checks when path filtering doesn;'t trigger the other job -# https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks - -name: tester - -on: - push: - branches: - - "main" - paths-ignore: - - '**.go' - - 'go.*' - - '.github/workflows/test.yml' - pull_request: - types: - - opened - - reopened - - synchronize - - ready_for_review - branches: - - "main" - paths-ignore: - - '**.go' - - 'go.*' - - '.github/workflows/test.yml' - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - test: - if: github.event.pull_request.draft == false - name: runner / gotest - runs-on: ubuntu-22.04 - steps: - - run: 'echo "No build required"' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f4074481b8..ea37bc2544 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,10 +4,6 @@ on: push: branches: - "main" - paths: - - '**.go' - - 'go.*' - - '.github/workflows/test.yml' pull_request: types: - opened @@ -16,22 +12,42 @@ on: - ready_for_review branches: - "main" - paths: - - '**.go' - - 'go.*' - - '.github/workflows/test.yml' - + concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: - test: + changes: + outputs: + should-run-tests: ${{ steps.changes.outputs.go == 'true' }} if: github.event.pull_request.draft == false + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: dorny/paths-filter@v2 + id: changes + with: + filters: | + go: + - '**.go' + - 'go.*' + - '.github/workflows/test.yml' + test: + needs: [changes] + if: needs.changes.outputs.should-run-tests == 'true' name: runner / gotest runs-on: ubuntu-22.04 container: ghcr.io/runatlantis/testing-env:latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: make test-all - run: make check-fmt + + skip-test: + needs: [changes] + if: needs.changes.outputs.should-run-tests == 'false' + name: runner / gotest + runs-on: ubuntu-22.04 + steps: + - run: 'echo "No build required"' diff --git a/.github/workflows/testing-env-image.yml b/.github/workflows/testing-env-image.yml index 0ab2157170..cc3b03fa69 100644 --- a/.github/workflows/testing-env-image.yml +++ b/.github/workflows/testing-env-image.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v2 @@ -33,7 +33,7 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Login to Packages Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} @@ -41,7 +41,7 @@ jobs: - run: echo "TODAY=$(date +"%Y.%m.%d")" >> $GITHUB_ENV - name: Build and push testing-env:${{env.TODAY}} image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: cache-from: type=gha cache-to: type=gha,mode=max diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 48a0700bf1..56f14f2683 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -35,7 +35,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-node@v3 with: diff --git a/Dockerfile b/Dockerfile index 10ebe3d38f..66a2a06c89 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ ARG DEBIAN_TAG=12.1-slim # Stage 1: build artifact and download deps -FROM golang:1.21.0-alpine AS builder +FROM golang:1.21.1-alpine AS builder ARG ATLANTIS_VERSION=dev ENV ATLANTIS_VERSION=${ATLANTIS_VERSION} @@ -60,7 +60,7 @@ WORKDIR /tmp/build # install conftest # renovate: datasource=github-releases depName=open-policy-agent/conftest -ENV DEFAULT_CONFTEST_VERSION=0.44.1 +ENV DEFAULT_CONFTEST_VERSION=0.45.0 SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN AVAILABLE_CONFTEST_VERSIONS=${DEFAULT_CONFTEST_VERSION} && \ case ${TARGETPLATFORM} in \ @@ -121,7 +121,7 @@ RUN case ${TARGETPLATFORM} in \ # install terraform binaries # renovate: datasource=github-releases depName=hashicorp/terraform versioning=hashicorp -ENV DEFAULT_TERRAFORM_VERSION=1.5.5 +ENV DEFAULT_TERRAFORM_VERSION=1.5.7 # In the official Atlantis image, we only have the latest of each Terraform version. # Each binary is about 80 MB so we limit it to the 4 latest minor releases or fewer diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 0000000000..7503792329 --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,8 @@ +The current Maintainers Group for the [Atlantis] Project consists of: + +| Name | GitHub ID | Employer | Responsibilities | +| ------------- | --------- | -------- | ---------------- | +| Dylan Page | [GenPage](https://github.com/GenPage) | Autodesk | Maintainer | +| PePe Amengual | [jamengual](https://github.com/jamengual) | Slalom | Maintainer | +| Rui Chen | [chenrui333](https://github.com/chenrui333) | Meetup | Maintainer | +| Ronak | [nitrocode](https://github.com/nitrocode) |RB Consulting LLC | Contributor, Reviewer | \ No newline at end of file diff --git a/cmd/server.go b/cmd/server.go index 4604b5f0d1..e6d691c8a9 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -80,6 +80,7 @@ const ( EnableRegExpCmdFlag = "enable-regexp-cmd" EnableDiffMarkdownFormat = "enable-diff-markdown-format" ExecutableName = "executable-name" + FailOnPreWorkflowHookError = "fail-on-pre-workflow-hook-error" HideUnchangedPlanComments = "hide-unchanged-plan-comments" GHHostnameFlag = "gh-hostname" GHTeamAllowlistFlag = "gh-team-allowlist" @@ -96,6 +97,7 @@ const ( GitlabTokenFlag = "gitlab-token" GitlabUserFlag = "gitlab-user" GitlabWebhookSecretFlag = "gitlab-webhook-secret" // nolint: gosec + IncludeGitUntrackedFiles = "include-git-untracked-files" APISecretFlag = "api-secret" HidePrevPlanComments = "hide-prev-plan-comments" QuietPolicyChecks = "quiet-policy-checks" @@ -457,6 +459,10 @@ var boolFlags = map[string]boolFlag{ description: "Enable Atlantis to format Terraform plan output into a markdown-diff friendly format for color-coding purposes.", defaultValue: false, }, + FailOnPreWorkflowHookError: { + description: "Fail and do not run the requested Atlantis command if any of the pre workflow hooks error.", + defaultValue: false, + }, GHAllowMergeableBypassApply: { description: "Feature flag to enable functionality to allow mergeable check to ignore apply required check", defaultValue: false, @@ -470,6 +476,10 @@ var boolFlags = map[string]boolFlag{ "VCS support is limited to: GitHub.", defaultValue: false, }, + IncludeGitUntrackedFiles: { + description: "Include git untracked files in the Atlantis modified file scope.", + defaultValue: false, + }, ParallelPlanFlag: { description: "Run plan operations in parallel.", defaultValue: false, diff --git a/docker-compose.yml b/docker-compose.yml index a1b5230159..ab2b2f1cab 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,7 +15,7 @@ services: depends_on: - atlantis redis: - image: redis:7.0-alpine + image: redis:7.2-alpine restart: always ports: - '6379:6379' diff --git a/e2e/e2e.go b/e2e/e2e.go index 3d4a44211b..233259c813 100644 --- a/e2e/e2e.go +++ b/e2e/e2e.go @@ -20,7 +20,7 @@ import ( "os/exec" "time" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" ) type E2ETester struct { diff --git a/e2e/github.go b/e2e/github.go index 2cc67215eb..f53374a535 100644 --- a/e2e/github.go +++ b/e2e/github.go @@ -16,7 +16,7 @@ package main import ( "context" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" ) type GithubClient struct { diff --git a/e2e/go.mod b/e2e/go.mod index 93aa94c370..f085bc0676 100644 --- a/e2e/go.mod +++ b/e2e/go.mod @@ -3,20 +3,20 @@ module github.com/runatlantis/atlantis/e2e go 1.21 require ( - github.com/google/go-github/v53 v53.2.0 + github.com/google/go-github/v54 v54.0.0 github.com/hashicorp/go-multierror v1.1.1 ) require ( github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/cloudflare/circl v1.3.3 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sys v0.8.0 // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/net v0.14.0 // indirect + golang.org/x/oauth2 v0.11.0 // indirect + golang.org/x/sys v0.11.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.28.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect ) diff --git a/e2e/go.sum b/e2e/go.sum index c5260cff7d..00e9017760 100644 --- a/e2e/go.sum +++ b/e2e/go.sum @@ -6,14 +6,14 @@ github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEM github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +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/google/go-cmp v0.5.2/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.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v53 v53.2.0 h1:wvz3FyF53v4BK+AsnvCmeNhf8AkTaeh2SoYu/XUvTtI= -github.com/google/go-github/v53 v53.2.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSXGt7mOsAWEloao= +github.com/google/go-github/v54 v54.0.0 h1:OZdXwow4EAD5jEo5qg+dGFH2DpkyZvVsAehjvJuUL/c= +github.com/google/go-github/v54 v54.0.0/go.mod h1:Sw1LXWHhXRZtzJ9LI5fyJg9wbQzYvFhW8W5P2yaAQ7s= 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/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -23,20 +23,20 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +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/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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= @@ -47,5 +47,5 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 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.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= diff --git a/e2e/main.go b/e2e/main.go index eba896ad90..a110434ccd 100644 --- a/e2e/main.go +++ b/e2e/main.go @@ -21,7 +21,7 @@ import ( "fmt" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" multierror "github.com/hashicorp/go-multierror" ) diff --git a/go.mod b/go.mod index 887cdcc3ca..6dfc6a6da3 100644 --- a/go.mod +++ b/go.mod @@ -5,36 +5,36 @@ go 1.21 require ( github.com/Masterminds/sprig/v3 v3.2.3 github.com/alicebob/miniredis/v2 v2.30.5 - github.com/bradleyfalzon/ghinstallation/v2 v2.6.0 + github.com/bradleyfalzon/ghinstallation/v2 v2.7.0 github.com/briandowns/spinner v1.23.0 github.com/cactus/go-statsd-client/v5 v5.1.0 github.com/go-ozzo/ozzo-validation v3.6.0+incompatible - github.com/go-playground/validator/v10 v10.15.0 + github.com/go-playground/validator/v10 v10.15.4 github.com/go-test/deep v1.1.0 github.com/golang-jwt/jwt/v5 v5.0.0 - github.com/google/go-github/v53 v53.2.0 + github.com/google/go-github/v54 v54.0.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.3.1 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/hashicorp/go-getter/v2 v2.2.1 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-version v1.6.0 - github.com/hashicorp/golang-lru/v2 v2.0.5 - github.com/hashicorp/terraform-config-inspect v0.0.0-20230808231734-f15f31bf62b3 + github.com/hashicorp/golang-lru/v2 v2.0.6 + github.com/hashicorp/terraform-config-inspect v0.0.0-20230825013512-b800820f61b8 github.com/kr/pretty v0.3.1 github.com/mcdafydd/go-azuredevops v0.12.1 github.com/microcosm-cc/bluemonday v1.0.25 github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db github.com/mitchellh/go-homedir v1.1.0 - github.com/moby/patternmatcher v0.5.0 + github.com/moby/patternmatcher v0.6.0 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/petergtz/pegomock/v4 v4.0.0 github.com/pkg/errors v0.9.1 - github.com/redis/go-redis/v9 v9.0.5 + github.com/redis/go-redis/v9 v9.1.0 github.com/remeh/sizedwaitgroup v1.0.0 github.com/shurcooL/githubv4 v0.0.0-20230704064427-599ae7bbf278 - github.com/slack-go/slack v0.12.2 + github.com/slack-go/slack v0.12.3 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.16.0 @@ -42,11 +42,11 @@ require ( github.com/uber-go/tally/v4 v4.1.7 github.com/urfave/negroni/v3 v3.0.0 github.com/warrensbox/terraform-switcher v0.1.1-0.20221027055942-201c8e92e997 - github.com/xanzy/go-gitlab v0.90.0 + github.com/xanzy/go-gitlab v0.91.1 go.etcd.io/bbolt v1.3.7 go.uber.org/zap v1.25.0 - golang.org/x/term v0.11.0 - golang.org/x/text v0.12.0 + golang.org/x/term v0.12.0 + golang.org/x/text v0.13.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -55,7 +55,7 @@ require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/hashicorp/hcl/v2 v2.17.0 + github.com/hashicorp/hcl/v2 v2.18.0 github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29 // indirect @@ -70,6 +70,7 @@ require ( github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1 // indirect github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -84,6 +85,7 @@ require ( github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-github/v55 v55.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -121,13 +123,13 @@ require ( github.com/yuin/gopher-lua v1.1.0 // indirect github.com/zclconf/go-cty v1.13.2 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.11.0 // indirect - golang.org/x/net v0.12.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sys v0.11.0 // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/net v0.14.0 // indirect + golang.org/x/oauth2 v0.11.0 // indirect + golang.org/x/sys v0.12.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/protobuf v1.31.0 // 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 a88013a7b5..2c38c0d0db 100644 --- a/go.sum +++ b/go.sum @@ -23,7 +23,6 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= @@ -62,6 +61,8 @@ github.com/alicebob/miniredis/v2 v2.30.5 h1:3r6kTHdKnuP4fkS8k2IrvSfxpxUTcW1SOL0w github.com/alicebob/miniredis/v2 v2.30.5/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= +github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= +github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= @@ -74,12 +75,12 @@ 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/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= -github.com/bradleyfalzon/ghinstallation/v2 v2.6.0 h1:IRY7Xy588KylkoycsUhFpW7cdGpy5Y5BPsz4IfuJtGk= -github.com/bradleyfalzon/ghinstallation/v2 v2.6.0/go.mod h1:oQ3etOwN3TRH4EwgW5/7MxSVMGlMlzG/O8TU7eYdoSk= +github.com/bradleyfalzon/ghinstallation/v2 v2.7.0 h1:ranXaC3Zz/F6G/f0Joj3LrFp2OzOKfJZev5Q7OaMc88= +github.com/bradleyfalzon/ghinstallation/v2 v2.7.0/go.mod h1:ymxfmloxXBFXvvF1KpeUhOQM6Dfz9NYtfvTiJyk82UE= github.com/briandowns/spinner v1.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A= github.com/briandowns/spinner v1.23.0/go.mod h1:rPG4gmXeN3wQV/TsAY4w8lPdIM6RX3yqeBQJSrbXjuE= -github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao= -github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= +github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0= +github.com/bsm/ginkgo/v2 v2.9.5/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= @@ -145,8 +146,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o 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.15.0 h1:nDU5XeOKtB3GEa+uB7GNYwhVKsgjAR7VgKoNB6ryXfw= -github.com/go-playground/validator/v10 v10.15.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.15.4 h1:zMXza4EpOdooxPel5xDqXEdXG5r+WggpvnAKMsalBjs= +github.com/go-playground/validator/v10 v10.15.4/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= @@ -200,11 +201,12 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/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.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v53 v53.2.0 h1:wvz3FyF53v4BK+AsnvCmeNhf8AkTaeh2SoYu/XUvTtI= -github.com/google/go-github/v53 v53.2.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSXGt7mOsAWEloao= +github.com/google/go-github/v54 v54.0.0 h1:OZdXwow4EAD5jEo5qg+dGFH2DpkyZvVsAehjvJuUL/c= +github.com/google/go-github/v54 v54.0.0/go.mod h1:Sw1LXWHhXRZtzJ9LI5fyJg9wbQzYvFhW8W5P2yaAQ7s= +github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLNb9x9cg= +github.com/google/go-github/v55 v55.0.0/go.mod h1:JLahOTA1DnXzhxEymmFF5PP2tSS9JVNj68mSZNDwskA= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= @@ -229,8 +231,8 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/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/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= @@ -261,14 +263,14 @@ github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mO github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 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/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= -github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/golang-lru/v2 v2.0.6 h1:3xi/Cafd1NaoEnS/yDssIiuVeDVywU0QdFGl3aQaQHM= +github.com/hashicorp/golang-lru/v2 v2.0.6/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= 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/hcl/v2 v2.17.0 h1:z1XvSUyXd1HP10U4lrLg5e0JMVz6CPaJvAgxM0KNZVY= -github.com/hashicorp/hcl/v2 v2.17.0/go.mod h1:gJyW2PTShkJqQBKpAmPO3yxMxIuoXkOF2TpqXzrQyx4= -github.com/hashicorp/terraform-config-inspect v0.0.0-20230808231734-f15f31bf62b3 h1:1uP3RA50ayEcTrHJtHaqubpW66KkXKIYXHP1+79dbMc= -github.com/hashicorp/terraform-config-inspect v0.0.0-20230808231734-f15f31bf62b3/go.mod h1:l8HcFPm9cQh6Q0KSWoYPiePqMvRFenybP1CH2MjKdlg= +github.com/hashicorp/hcl/v2 v2.18.0 h1:wYnG7Lt31t2zYkcquwgKo6MWXzRUDIeIVU5naZwHLl8= +github.com/hashicorp/hcl/v2 v2.18.0/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE= +github.com/hashicorp/terraform-config-inspect v0.0.0-20230825013512-b800820f61b8 h1:SzE5lAYh9XXR3b1q3p3uBNqEY+syiiLZiFCIvr/JTsg= +github.com/hashicorp/terraform-config-inspect v0.0.0-20230825013512-b800820f61b8/go.mod h1:l8HcFPm9cQh6Q0KSWoYPiePqMvRFenybP1CH2MjKdlg= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= @@ -337,8 +339,8 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo= -github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 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= @@ -388,8 +390,8 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= -github.com/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o= -github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= +github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY= +github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c= github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E= github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -410,8 +412,8 @@ github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29/go.mod h1:AuYgA5K github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ= -github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= +github.com/slack-go/slack v0.12.3 h1:92/dfFU8Q5XP6Wp5rr5/T5JHLM5c5Smtn53fhToAP88= +github.com/slack-go/slack v0.12.3/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -453,8 +455,8 @@ github.com/urfave/negroni/v3 v3.0.0 h1:Vo8CeZfu1lFR9gW8GnAb6dOGCJyijfil9j/jKKc/J github.com/urfave/negroni/v3 v3.0.0/go.mod h1:jWvnX03kcSjDBl/ShB0iHvx5uOs7mAzZXW+JvJ5XYAs= github.com/warrensbox/terraform-switcher v0.1.1-0.20221027055942-201c8e92e997 h1:be5WC0FHdhimAhe2G3DPhduX117RM8qdTMYCMHDt4DM= github.com/warrensbox/terraform-switcher v0.1.1-0.20221027055942-201c8e92e997/go.mod h1:saryXNaL624mlulV138FP+HhVw7IpvETUXLS3nTvH1g= -github.com/xanzy/go-gitlab v0.90.0 h1:j8ZUHfLfXdnC+B8njeNaW/kM44c1zw8fiuNj7D+qQN8= -github.com/xanzy/go-gitlab v0.90.0/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw= +github.com/xanzy/go-gitlab v0.91.1 h1:gnV57IPGYywWer32oXKBcdmc8dVxeKl3AauV8Bu17rw= +github.com/xanzy/go-gitlab v0.91.1/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -494,8 +496,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +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/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -575,8 +577,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= 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/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -589,8 +591,8 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= 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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -659,16 +661,18 @@ golang.org/x/sys v0.3.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.8.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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -681,8 +685,9 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -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/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -834,9 +839,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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= diff --git a/package.json b/package.json index bb9c39da98..9b5907ea0f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "license": "Apache-2.0", "devDependencies": { "@vuepress/plugin-docsearch": "2.0.0-beta.66", - "@vuepress/plugin-google-analytics": "2.0.0-beta.66", + "@vuepress/plugin-google-analytics": "2.0.0-beta.67", "vuepress": "2.0.0-beta.66" }, "scripts": { diff --git a/runatlantis.io/docs/custom-workflows.md b/runatlantis.io/docs/custom-workflows.md index 3ba12e1325..a6ee35ab6a 100644 --- a/runatlantis.io/docs/custom-workflows.md +++ b/runatlantis.io/docs/custom-workflows.md @@ -161,16 +161,17 @@ workflows: - run: terraform apply $PLANFILE ``` -### cdktf -Here are the requirements to enable [cdktf](https://developer.hashicorp.com/terraform/cdktf) - -- A custom image with `cdktf` installed -- The autoplan file updated to trigger off of `**/cdk.tf.json` -- The output of `cdktf synth` has to be committed to the pull request -- Optional: Use `pre_workflow_hooks` to run `cdktf synth` as a double check +### CDKTF +Here are the requirements to enable [CDKTF](https://developer.hashicorp.com/terraform/cdktf) + +- A custom image with `CDKTF` installed +- Add `**/cdk.tf.json` to the list of Atlantis autoplan files. +- Set the `atlantis-include-git-untracked-files` flag so that the Terraform files dynamically generated +by CDKTF will be add to the Atlantis modified file list. +- Use `pre_workflow_hooks` to run `cdktf synth` - Optional: There isn't a requirement to use a repo `atlantis.yaml` but one can be leveraged if needed. -#### custom image +#### Custom Image ```dockerfile # Dockerfile @@ -179,11 +180,12 @@ FROM ghcr.io/runatlantis/atlantis:v0.19.7 RUN apk add npm && npm i -g cdktf-cli ``` -#### server config +#### Server Config ```bash # env variables ATLANTIS_AUTOPLAN_FILE_LIST="**/*.tf,**/*.tfvars,**/*.tfvars.json,**/cdk.tf.json" +ATLANTIS_INCLUDE_GIT_UNTRACKED_FILES=true ``` OR @@ -192,9 +194,10 @@ OR ```yaml # config.yaml autoplan-file-list: "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/cdk.tf.json" +include-git-untracked-files: true ``` -#### server repo config +#### Server Repo Config Use `pre_workflow_hooks` @@ -204,32 +207,39 @@ Use `pre_workflow_hooks` repos: - id: /.*cdktf.*/ pre_workflow_hooks: - - run: npm i && cdktf get && cdktf synth + - run: npm i && cdktf get && cdktf synth --output ci-cdktf.out ``` -#### repo structure +**Note:** don't use the default `cdktf.out` directory that CDKTF uses, as this should be in the `.gitignore` list of the +repo, so that locally generated files are not checked in. + +#### Repo Structure -This is the git repo structure after running `cdktf synth`. The `cdk.tf.json` files contain the HCL that atlantis can run. +This is the git repo structure after running `cdktf synth`. The `cdk.tf.json` files contain the Terraform configuration +that atlantis can run. ```bash $ tree --gitignore . ├── cdktf.json -├── cdktf.out +├── ci-cdktf.out │ ├── manifest.json │ └── stacks │ └── eks │ └── cdk.tf.json ``` -#### workflow +#### Workflow -1. Container orchestrator (k8s/fargate/ecs/etc) uses the custom docker image of atlantis with `cdktf` installed with the `--autoplan-file-list` to trigger on json files -1. PR branch is pushed up containing `cdktf` changes and generated hcl json -1. Atlantis checks out the branch in the repo -1. Atlantis runs the `npm i && cdktf get && cdktf synth` command in the repo root as a step in `pre_workflow_hooks` (as a double check described above) -1. Atlantis detects the change to the generated hcl json files in a number of `dir`s -1. Atlantis then runs `terraform` workflows in the respective `dir`s as usual +1. Container orchestrator (k8s/fargate/ecs/etc) uses the custom docker image of atlantis with `cdktf` installed with +the `--autoplan-file-list` to trigger on `cdk.tf.json` files and `--include-git-untracked-files` set to include the +CDKTF dynamically generated Terraform files in the Atlantis plan. +1. PR branch is pushed up containing `cdktf` code changes. +1. Atlantis checks out the branch in the repo. +1. Atlantis runs the `npm i && cdktf get && cdktf synth` command in the repo root as a step in `pre_workflow_hooks`, +generating the `cdk.tf.json` Terraform files. +1. Atlantis detects the `cdk.tf.json` untracked files in a number of directories. +1. Atlantis then runs `terraform` workflows in the respective directories as usual. ### Terragrunt Atlantis supports running custom commands in place of the default Atlantis diff --git a/runatlantis.io/docs/pre-workflow-hooks.md b/runatlantis.io/docs/pre-workflow-hooks.md index b4eb852bf3..08f14e351d 100644 --- a/runatlantis.io/docs/pre-workflow-hooks.md +++ b/runatlantis.io/docs/pre-workflow-hooks.md @@ -15,9 +15,12 @@ workflows](custom-workflows.html#custom-run-command) in several ways. Pre workflow hooks can only be specified in the Server-Side Repo Config under the `repos` key. + ::: tip Note -`pre-workflow-hooks` do not prevent Atlantis from executing its -workflows(`plan`, `apply`) even if a `run` command exits with an error. +By default, `pre-workflow-hooks` do not prevent Atlantis from executing its +workflows(`plan`, `apply`) even if a `run` command exits with an error. This +behavior can be changed by setting the [fail-on-pre-workflow-hook-error](server-configuration.html#fail-on-pre-workflow-hook-error) +flag in the Atlantis server configuration. ::: ## Use Cases diff --git a/runatlantis.io/docs/server-configuration.md b/runatlantis.io/docs/server-configuration.md index bca4e04da4..ccdd328330 100644 --- a/runatlantis.io/docs/server-configuration.md +++ b/runatlantis.io/docs/server-configuration.md @@ -143,7 +143,7 @@ Values are chosen in this order: ::: warning NOTE -By default, changes to modules will not trigger autoplanning. See the flags below. +By default, changes to modules will not trigger autoplanning. See the flags below. ::: ::: warning NOTE @@ -159,7 +159,7 @@ ATLANTIS_AUTOPLAN_MODULES=true ``` Defaults to `false`. When set to `true`, Atlantis will trace the local modules of included projects. -Included project are projects with files included by `--autoplan-file-list`. +Included project are projects with files included by `--autoplan-file-list`. After tracing, Atlantis will plan any project that includes a changed module. This is equivalent to setting `--autoplan-modules-from-projects` to the value of `--autoplan-file-list`. See below. @@ -175,8 +175,8 @@ atlantis server --autoplan-modules-from-projects='**/init.tf' ATLANTIS_AUTOPLAN_MODULES_FROM_PROJECTS='**/init.tf' ``` -Enables auto-planing of projects when a module dependency in the same repository has changed. -This is a list of file patterns like `autoplan-file-list`. +Enables auto-planing of projects when a module dependency in the same repository has changed. +This is a list of file patterns like `autoplan-file-list`. These patterns select **projects** to index based on the files matched. The index maps modules to the projects that depends on them, including projects that include the module via other modules. When a module file matching `autoplan-file-list` changes, @@ -216,7 +216,7 @@ and set `--autoplan-modules` to `false`. ``` Azure DevOps basic authentication password for inbound webhooks (see [docs](https://docs.microsoft.com/en-us/azure/devops/service-hooks/authorize?view=azure-devops)). - + ::: warning SECURITY WARNING If not specified, Atlantis won't be able to validate that the incoming webhook call came from your Azure DevOps org. This means that an @@ -326,7 +326,7 @@ and set `--autoplan-modules` to `false`. Terraform binaries here. If Atlantis loses this directory, [locks](locking.html) will be lost and unapplied plans will be lost. - Note that the atlantis user is restricted to `~/.atlantis`. + Note that the atlantis user is restricted to `~/.atlantis`. If you set the `--data-dir` flag to a path outside of Atlantis its home directory, ensure that you grant the atlantis user the correct permissions. ### `--default-tf-version` @@ -395,9 +395,9 @@ and set `--autoplan-modules` to `false`. ATLANTIS_ENABLE_REGEXP_CMD=true ``` Enable Atlantis to use regular expressions to run plan/apply commands against defined project names when `-p` flag is passed with it. - + This can be used to run all defined projects (with the `name` key) in `atlantis.yaml` using `atlantis plan -p .*`. - + The flag will only allow the regexes listed in the [`allowed_regexp_prefixes`](https://www.runatlantis.io/docs/repo-level-atlantis-yaml.html#reference) key defined in the repo `atlantis.yaml` file. If the key is undefined, its value defaults to `[]` which will allow any regex. This will not work with `-d` yet and to use `-p` the repo projects must be defined in the repo `atlantis.yaml` file. @@ -429,13 +429,22 @@ and set `--autoplan-modules` to `false`. This is useful when running multiple Atlantis servers against a single repository. +### `--fail-on-pre-workflow-hook-error` + ```bash + atlantis server --fail-on-pre-workflow-hook-error + # or + ATLANTIS_FAIL_ON_PRE_WORKFLOW_HOOK_ERROR=true + ``` + + Fail and do not run the requested Atlantis command if any of the pre workflow hooks error. + ### `--hide-unchanged-plan-comments` ```bash atlantis server --hide-unchanged-plan-comments # or ATLANTIS_HIDE_UNCHANGED_PLAN_COMMENTS=true ``` -Remove no-changes plan comments from the pull request. +Remove no-changes plan comments from the pull request. This is useful when you have many projects and want to keep the pull request clean from useless comments. @@ -515,7 +524,7 @@ This is useful when you have many projects and want to keep the pull request cle # or ATLANTIS_GH_APP_SLUG="myappslug" ``` - A slugged version of GitHub app name shown in pull requests comments, etc (not `Atlantis App` but something like `atlantis-app`). Atlantis uses the value of this parameter to identify the comments it has left on GitHub pull requests. This is used for functions such as `--hide-prev-plan-comments`. + A slugged version of GitHub app name shown in pull requests comments, etc (not `Atlantis App` but something like `atlantis-app`). Atlantis uses the value of this parameter to identify the comments it has left on GitHub pull requests. This is used for functions such as `--hide-prev-plan-comments`. You need to obtain this value from your GitHub app, one way is to go to your App settings and open "Public page" from the left sidebar. Your `--gh-app-slug` value will be the last part of the URL, e.g `https://github.com/apps/`. ### `--gh-app-key-file` ```bash @@ -544,13 +553,13 @@ This is useful when you have many projects and want to keep the pull request cle ATLANTIS_GH_TEAM_ALLOWLIST="myteam:plan, secteam:apply, DevOps Team:apply, DevOps Team:import" ``` In versions v0.21.0 and later, the GitHub team name can be a name or a slug. - + In versions v0.20.1 and below, the Github team name required the case sensitive team name. - + Comma-separated list of GitHub teams and permission pairs. - + By default, any team can plan and apply. - + ::: warning NOTE You should use the Team name as the variable, not the slug, even if it has spaces or special characters. i.e., "Engineering Team:plan, Infrastructure Team:apply" @@ -564,11 +573,6 @@ This is useful when you have many projects and want to keep the pull request cle ``` Feature flag to enable ability to use `mergeable` mode with required apply status check. - ::: warning NOTE - If there aren't any required checks set in the Github branch protection settings then this will cause atlantis to fail. - See issue https://github.com/runatlantis/atlantis/issues/2663. - ::: - ### `--gitlab-hostname` ```bash atlantis server --gitlab-hostname="my.gitlab.enterprise.com" @@ -622,6 +626,16 @@ This is useful when you have many projects and want to keep the pull request cle Hide previous plan comments to declutter PRs. This is only supported in GitHub and GitLab currently. This is not enabled by default. +### `--include-git-untracked-files` + ```bash + atlantis server --include-git-untracked-files + # or + ATLANTIS_INCLUDE_GIT_UNTRACKED_FILES=true + ``` + Include git untracked files in the Atlantis modified file list. + Used for example with CDKTF pre-workflow hooks that dynamically generate + Terraform files. + ### `--locking-db-type` ```bash atlantis server --locking-db-type="" @@ -675,7 +689,7 @@ This is useful when you have many projects and want to keep the pull request cle # or ATLANTIS_PARALLEL_PLAN=true ``` - Whether to run plan operations in parallel. Defaults to `false`. Explicit declaration in [repo config](repo-level-atlantis-yaml.html#run-plans-and-applies-in-parallel) takes precidence. + Whether to run plan operations in parallel. Defaults to `false`. Explicit declaration in [repo config](repo-level-atlantis-yaml.html#run-plans-and-applies-in-parallel) takes precedence. ### `--parallel-apply` ```bash @@ -683,7 +697,7 @@ This is useful when you have many projects and want to keep the pull request cle # or ATLANTIS_PARALLEL_APPLY=true ``` - Whether to run apply operations in parallel. Defaults to `false`. Explicit declaration in [repo config](repo-level-atlantis-yaml.html#run-plans-and-applies-in-parallel) takes precidence. + Whether to run apply operations in parallel. Defaults to `false`. Explicit declaration in [repo config](repo-level-atlantis-yaml.html#run-plans-and-applies-in-parallel) takes precedence. ### `--port` ```bash @@ -945,7 +959,7 @@ Setting this to `false` can be useful in an air-gapped environment where a downl An alternative URL to download Terraform versions if they are missing. Useful in an airgapped environment where releases.hashicorp.com is not available. Directory structure of the custom endpoint should match that of releases.hashicorp.com. - + This has no impact if `--tf-download` is set to `false`. ### `--tfe-hostname` @@ -1004,9 +1018,9 @@ Setting this to `false` can be useful in an air-gapped environment where a downl ``` Write out a .git-credentials file with the provider user and token to allow cloning private modules over HTTPS or SSH. See [here](https://git-scm.com/docs/git-credential-store) for more information. - + Follow the `git::ssh` syntax to avoid using a custom `.gitconfig` with an `insteadOf`. - + ```hcl module "private_submodule" { source = "git::ssh://git@github.com////modules/?ref=v1.2.3" @@ -1014,7 +1028,7 @@ Setting this to `false` can be useful in an air-gapped environment where a downl # ... } ``` - + ::: warning SECURITY WARNING This does write secrets to disk and should only be enabled in a secure environment. ::: diff --git a/runatlantis.io/docs/server-side-repo-config.md b/runatlantis.io/docs/server-side-repo-config.md index 4c616da66c..83cd3ddc5a 100644 --- a/runatlantis.io/docs/server-side-repo-config.md +++ b/runatlantis.io/docs/server-side-repo-config.md @@ -550,7 +550,7 @@ If you set a workflow with the key `default`, it will override this. | Key | Type | Default | Required | Description | |------------------------|---------------------------|---------|-----------|------------------------------------------| | statsd | [Statsd](#statsd) | none | no | Statsd metrics provider | -| prometheus | [Prometheus](#prometheus) | none | no | Statsd metrics provider | +| prometheus | [Prometheus](#prometheus) | none | no | Prometheus metrics provider | ### Statsd diff --git a/runatlantis.io/docs/using-atlantis.md b/runatlantis.io/docs/using-atlantis.md index de03dde278..8009440a14 100644 --- a/runatlantis.io/docs/using-atlantis.md +++ b/runatlantis.io/docs/using-atlantis.md @@ -79,6 +79,19 @@ atlantis plan -d dir -- -var foo='bar' ``` If you always need to append a certain flag, see [Custom Workflow Use Cases](custom-workflows.html#adding-extra-arguments-to-terraform-commands). +### Using the -destroy Flag + +#### Example +To perform a destructive plan that will destroy resources you can use the `-destroy` flag like this: + +```bash +atlantis plan -- -destroy +atlantis plan -d dir -- -destroy +``` +::: warning NOTE +The `-destroy` flag generates a destroy plan, If this plan is applied it can result in data loss or service disruptions. Ensure that you have thoroughly reviewed your Terraform configuration and intend to remove the specified resources before using this flag. +::: + --- ## atlantis apply ```bash diff --git a/runatlantis.io/docs/using-slack-hooks.md b/runatlantis.io/docs/using-slack-hooks.md index c10706ecc1..c75c243fca 100644 --- a/runatlantis.io/docs/using-slack-hooks.md +++ b/runatlantis.io/docs/using-slack-hooks.md @@ -41,6 +41,7 @@ In your Atlantis configuration you can now add the following: webhooks: - event: apply workspace-regex: .* + branch-regex: .* kind: slack channel: my-channel ``` @@ -56,6 +57,7 @@ config: | webhooks: - event: apply workspace-regex: .* + branch-regex: .* kind: slack channel: my-channel ``` diff --git a/server/controllers/events/events_controller.go b/server/controllers/events/events_controller.go index c4f1b53474..10b8daf1f5 100644 --- a/server/controllers/events/events_controller.go +++ b/server/controllers/events/events_controller.go @@ -19,7 +19,7 @@ import ( "net/http" "strings" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" "github.com/mcdafydd/go-azuredevops/azuredevops" "github.com/microcosm-cc/bluemonday" "github.com/pkg/errors" @@ -587,7 +587,8 @@ func (e *VCSEventsController) handleCommentEvent(logger logging.SimpleLogging, b } } - logger.Debug("executing command") + logger.Info("Running comment command '%v' on repo '%v', pull request: %v for user '%v'.", + parseResult.Command.Name, baseRepo.FullName, pullNum, user.Username) if !e.TestingMode { // Respond with success and then actually execute the command asynchronously. // We use a goroutine so that this function returns and the connection is diff --git a/server/controllers/events/events_controller_e2e_test.go b/server/controllers/events/events_controller_e2e_test.go index 64f499ac11..9fa6efaf1e 100644 --- a/server/controllers/events/events_controller_e2e_test.go +++ b/server/controllers/events/events_controller_e2e_test.go @@ -13,7 +13,7 @@ import ( "strings" "testing" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" "github.com/hashicorp/go-version" . "github.com/petergtz/pegomock/v4" @@ -1323,6 +1323,7 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, false, + false, statsScope, logger, terraformClient, diff --git a/server/controllers/events/events_controller_test.go b/server/controllers/events/events_controller_test.go index 1aab8f246c..d018880aaf 100644 --- a/server/controllers/events/events_controller_test.go +++ b/server/controllers/events/events_controller_test.go @@ -25,12 +25,13 @@ import ( "strings" "testing" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" "github.com/mcdafydd/go-azuredevops/azuredevops" . "github.com/petergtz/pegomock/v4" events_controllers "github.com/runatlantis/atlantis/server/controllers/events" "github.com/runatlantis/atlantis/server/controllers/events/mocks" "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" emocks "github.com/runatlantis/atlantis/server/events/mocks" "github.com/runatlantis/atlantis/server/events/models" vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" @@ -347,15 +348,17 @@ func TestPost_GithubCommentResponse(t *testing.T) { func TestPost_GitlabCommentSuccess(t *testing.T) { t.Log("when the event is a gitlab comment with a valid command we call the command handler") - e, _, gl, _, _, cr, _, _, _ := setup(t) + e, _, gl, _, _, cr, _, _, cp := setup(t) req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) req.Header.Set(gitlabHeader, "value") + cmd := events.CommentCommand{} When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeCommentEvent{}, nil) + When(cp.Parse(Any[string](), Eq(models.Gitlab))).ThenReturn(events.CommentParseResult{Command: &cmd}) w := httptest.NewRecorder() e.Post(w, req) ResponseContains(t, w, http.StatusOK, "Processing...") - cr.VerifyWasCalledOnce().RunCommentCommand(models.Repo{}, &models.Repo{}, nil, models.User{}, 0, nil) + cr.VerifyWasCalledOnce().RunCommentCommand(models.Repo{}, &models.Repo{}, nil, models.User{}, 0, &cmd) } func TestPost_GithubCommentSuccess(t *testing.T) { @@ -378,17 +381,18 @@ func TestPost_GithubCommentSuccess(t *testing.T) { } func TestPost_GithubCommentReaction(t *testing.T) { - t.Log("when the event is a github comment with a valid command we call the command handler") + t.Log("when the event is a github comment with a valid command we call the ReactToComment handler") e, v, _, _, p, _, _, vcsClient, cp := setup(t) req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) req.Header.Set(githubHeader, "issue_comment") - event := `{"action": "created", "comment": {"body": "@atlantis-bot help", "id": 1}}` + testComment := "atlantis plan" + event := fmt.Sprintf(`{"action": "created", "comment": {"body": "%v", "id": 1}}`, testComment) When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) baseRepo := models.Repo{} user := models.User{} - cmd := events.CommentCommand{} + cmd := events.CommentCommand{Name: command.Plan} When(p.ParseGithubIssueCommentEvent(Any[*github.IssueCommentEvent]())).ThenReturn(baseRepo, user, 1, nil) - When(cp.Parse("", models.Github)).ThenReturn(events.CommentParseResult{Command: &cmd}) + When(cp.Parse(testComment, models.Github)).ThenReturn(events.CommentParseResult{Command: &cmd}) w := httptest.NewRecorder() e.Post(w, req) ResponseContains(t, w, http.StatusOK, "Processing...") @@ -398,10 +402,12 @@ func TestPost_GithubCommentReaction(t *testing.T) { func TestPost_GilabCommentReaction(t *testing.T) { t.Log("when the event is a gitlab comment with a valid command we call the ReactToComment handler") - e, _, gl, _, _, _, _, vcsClient, _ := setup(t) + e, _, gl, _, _, _, _, vcsClient, cp := setup(t) req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) req.Header.Set(gitlabHeader, "value") + cmd := events.CommentCommand{} When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeCommentEvent{}, nil) + When(cp.Parse(Any[string](), Eq(models.Gitlab))).ThenReturn(events.CommentParseResult{Command: &cmd}) w := httptest.NewRecorder() e.Post(w, req) ResponseContains(t, w, http.StatusOK, "Processing...") @@ -685,12 +691,14 @@ func TestPost_AzureDevopsPullRequestWebhookTestIgnoreEvent(t *testing.T) { func TestPost_AzureDevopsPullRequestCommentPassingIgnores(t *testing.T) { t.Log("when the event should not be ignored it should pass through all ignore statements without error") - e, _, _, ado, _, _, _, _, _ := setup(t) + e, _, _, ado, _, _, _, _, cp := setup(t) + testComment := "atlantis plan" repo := models.Repo{} + cmd := events.CommentCommand{Name: command.Plan} When(e.Parser.ParseAzureDevopsRepo(Any[*azuredevops.GitRepository]())).ThenReturn(repo, nil) - - payload := `{ + When(cp.Parse(testComment, models.AzureDevops)).ThenReturn(events.CommentParseResult{Command: &cmd}) + payload := fmt.Sprintf(`{ "subscriptionId": "11111111-1111-1111-1111-111111111111", "notificationId": 1, "id": "22222222-2222-2222-2222-222222222222", @@ -703,14 +711,14 @@ func TestPost_AzureDevopsPullRequestCommentPassingIgnores(t *testing.T) { "comment": { "id": 1, "commentType": "text", - "content": "test" + "content": "%v" }, "pullRequest": { "pullRequestId": 1, "repository": {} } } - }` + }`, testComment) t.Run("Testing to see if comment passes ignore conditions", func(t *testing.T) { req, _ := http.NewRequest("GET", "", strings.NewReader(payload)) diff --git a/server/controllers/events/github_request_validator.go b/server/controllers/events/github_request_validator.go index 1d7c71e283..b318b172eb 100644 --- a/server/controllers/events/github_request_validator.go +++ b/server/controllers/events/github_request_validator.go @@ -19,7 +19,7 @@ import ( "io" "net/http" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" ) //go:generate pegomock generate --package mocks -o mocks/mock_github_request_validator.go GithubRequestValidator diff --git a/server/core/runtime/post_workflow_hook_runner_test.go b/server/core/runtime/post_workflow_hook_runner_test.go index f4db6fcf93..bbf22b4394 100644 --- a/server/core/runtime/post_workflow_hook_runner_test.go +++ b/server/core/runtime/post_workflow_hook_runner_test.go @@ -1,6 +1,7 @@ package runtime_test import ( + "fmt" "strings" "testing" @@ -18,6 +19,8 @@ func TestPostWorkflowHookRunner_Run(t *testing.T) { defaultShell := "sh" defaultShellArgs := "-c" + defautShellCommandNotFoundErrorFormat := commandNotFoundErrorFormat(defaultShell) + defaultUnterminatedStringError := unterminatedStringError(defaultShell, defaultShellArgs) cases := []struct { Command string @@ -63,7 +66,7 @@ func TestPostWorkflowHookRunner_Run(t *testing.T) { Command: "echo 'a", Shell: defaultShell, ShellArgs: defaultShellArgs, - ExpOut: "sh: 1: Syntax error: Unterminated quoted string\r\n", + ExpOut: defaultUnterminatedStringError, ExpErr: "exit status 2: running \"sh -c echo 'a\" in", ExpDescription: "", }, @@ -79,7 +82,7 @@ func TestPostWorkflowHookRunner_Run(t *testing.T) { Command: "lkjlkj", Shell: defaultShell, ShellArgs: defaultShellArgs, - ExpOut: "sh: 1: lkjlkj: not found\r\n", + ExpOut: fmt.Sprintf(defautShellCommandNotFoundErrorFormat, "lkjlkj"), ExpErr: "exit status 127: running \"sh -c lkjlkj\" in", ExpDescription: "", }, diff --git a/server/core/runtime/pre_workflow_hook_runner_test.go b/server/core/runtime/pre_workflow_hook_runner_test.go index e51d49e58e..ad8659cfa2 100644 --- a/server/core/runtime/pre_workflow_hook_runner_test.go +++ b/server/core/runtime/pre_workflow_hook_runner_test.go @@ -1,6 +1,8 @@ package runtime_test import ( + "fmt" + goruntime "runtime" "strings" "testing" @@ -14,10 +16,31 @@ import ( . "github.com/runatlantis/atlantis/testing" ) +func commandNotFoundErrorFormat(shell string) string { + // TODO: Add more GOOSs. Also I haven't done too much testing + // maybe the output here depends on other factors as well + if goruntime.GOOS == "darwin" { + return fmt.Sprintf("%s: %%s: command not found\r\n", shell) + } + return fmt.Sprintf("%s: 1: %%s: not found\r\n", shell) + +} + +func unterminatedStringError(shell, shellArgs string) string { + // TODO: Add more GOOSs. Also I haven't done too much testing + // maybe the output here depends on other factors as well + if goruntime.GOOS == "darwin" { + return fmt.Sprintf("%s: %s: line 0: unexpected EOF while looking for matching `''\r\n%s: %s: line 1: syntax error: unexpected end of file\r\n", shell, shellArgs, shell, shellArgs) + } + return fmt.Sprintf("%s: 1: Syntax error: Unterminated quoted string\r\n", shell) +} + func TestPreWorkflowHookRunner_Run(t *testing.T) { defaultShell := "sh" defaultShellArgs := "-c" + defautShellCommandNotFoundErrorFormat := commandNotFoundErrorFormat(defaultShell) + defaultUnterminatedStringError := unterminatedStringError(defaultShell, defaultShellArgs) cases := []struct { Command string @@ -63,7 +86,7 @@ func TestPreWorkflowHookRunner_Run(t *testing.T) { Command: "echo 'a", Shell: defaultShell, ShellArgs: defaultShellArgs, - ExpOut: "sh: 1: Syntax error: Unterminated quoted string\r\n", + ExpOut: defaultUnterminatedStringError, ExpErr: "exit status 2: running \"sh -c echo 'a\" in", ExpDescription: "", }, @@ -79,7 +102,7 @@ func TestPreWorkflowHookRunner_Run(t *testing.T) { Command: "lkjlkj", Shell: defaultShell, ShellArgs: defaultShellArgs, - ExpOut: "sh: 1: lkjlkj: not found\r\n", + ExpOut: fmt.Sprintf(defautShellCommandNotFoundErrorFormat, "lkjlkj"), ExpErr: "exit status 127: running \"sh -c lkjlkj\" in", ExpDescription: "", }, diff --git a/server/events/apply_command_runner_test.go b/server/events/apply_command_runner_test.go index 27117008a6..b4fe315496 100644 --- a/server/events/apply_command_runner_test.go +++ b/server/events/apply_command_runner_test.go @@ -4,7 +4,7 @@ import ( "errors" "testing" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" . "github.com/petergtz/pegomock/v4" "github.com/runatlantis/atlantis/server/core/db" "github.com/runatlantis/atlantis/server/core/locking" diff --git a/server/events/command_requirement_handler.go b/server/events/command_requirement_handler.go index dadb526a78..8af12bec54 100644 --- a/server/events/command_requirement_handler.go +++ b/server/events/command_requirement_handler.go @@ -22,7 +22,7 @@ func (a *DefaultCommandRequirementHandler) ValidatePlanProject(repoDir string, c switch req { case raw.ApprovedRequirement: if !ctx.PullReqStatus.ApprovalStatus.IsApproved { - return "Pull request must be approved by at least one person other than the author before running plan.", nil + return "Pull request must be approved according to the project's approval rules before running plan.", nil } case raw.MergeableRequirement: if !ctx.PullReqStatus.Mergeable { @@ -43,7 +43,7 @@ func (a *DefaultCommandRequirementHandler) ValidateApplyProject(repoDir string, switch req { case raw.ApprovedRequirement: if !ctx.PullReqStatus.ApprovalStatus.IsApproved { - return "Pull request must be approved by at least one person other than the author before running apply.", nil + return "Pull request must be approved according to the project's approval rules before running apply.", nil } // this should come before mergeability check since mergeability is a superset of this check. case valid.PoliciesPassedCommandReq: @@ -70,7 +70,7 @@ func (a *DefaultCommandRequirementHandler) ValidateImportProject(repoDir string, switch req { case raw.ApprovedRequirement: if !ctx.PullReqStatus.ApprovalStatus.IsApproved { - return "Pull request must be approved by at least one person other than the author before running import.", nil + return "Pull request must be approved according to the project's approval rules before running import.", nil } case raw.MergeableRequirement: if !ctx.PullReqStatus.Mergeable { diff --git a/server/events/command_requirement_handler_test.go b/server/events/command_requirement_handler_test.go index f76ff7254c..7a9891b07c 100644 --- a/server/events/command_requirement_handler_test.go +++ b/server/events/command_requirement_handler_test.go @@ -58,7 +58,7 @@ func TestAggregateApplyRequirements_ValidatePlanProject(t *testing.T) { ApprovalStatus: models.ApprovalStatus{IsApproved: false}, }, }, - wantFailure: "Pull request must be approved by at least one person other than the author before running plan.", + wantFailure: "Pull request must be approved according to the project's approval rules before running plan.", wantErr: assert.NoError, }, { @@ -142,7 +142,7 @@ func TestAggregateApplyRequirements_ValidateApplyProject(t *testing.T) { ApprovalStatus: models.ApprovalStatus{IsApproved: false}, }, }, - wantFailure: "Pull request must be approved by at least one person other than the author before running apply.", + wantFailure: "Pull request must be approved according to the project's approval rules before running apply.", wantErr: assert.NoError, }, { @@ -249,7 +249,7 @@ func TestAggregateApplyRequirements_ValidateImportProject(t *testing.T) { ApprovalStatus: models.ApprovalStatus{IsApproved: false}, }, }, - wantFailure: "Pull request must be approved by at least one person other than the author before running import.", + wantFailure: "Pull request must be approved according to the project's approval rules before running import.", wantErr: assert.NoError, }, { diff --git a/server/events/command_runner.go b/server/events/command_runner.go index e6d49e9a07..a61d63ee20 100644 --- a/server/events/command_runner.go +++ b/server/events/command_runner.go @@ -17,7 +17,7 @@ import ( "fmt" "strconv" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" "github.com/mcdafydd/go-azuredevops/azuredevops" "github.com/pkg/errors" "github.com/runatlantis/atlantis/server/core/config/valid" @@ -96,12 +96,15 @@ type DefaultCommandRunner struct { GithubPullGetter GithubPullGetter AzureDevopsPullGetter AzureDevopsPullGetter GitlabMergeRequestGetter GitlabMergeRequestGetter - DisableAutoplan bool - EventParser EventParsing - Logger logging.SimpleLogging - GlobalCfg valid.GlobalCfg - StatsScope tally.Scope - // AllowForkPRs controls whether we operate on pull requests from forks. + // User config option: Disables autoplan when a pull request is opened or updated. + DisableAutoplan bool + EventParser EventParsing + // User config option: Fail and do not run the Atlantis command request if any of the pre workflow hooks error + FailOnPreWorkflowHookError bool + Logger logging.SimpleLogging + GlobalCfg valid.GlobalCfg + StatsScope tally.Scope + // User config option: controls whether to operate on pull requests from forks. AllowForkPRs bool // ParallelPoolSize controls the size of the wait group used to run // parallel plans and applies (if enabled). @@ -110,7 +113,7 @@ type DefaultCommandRunner struct { // this in our error message back to the user on a forked PR so they know // how to enable this functionality. AllowForkPRsFlag string - // SilenceForkPRErrors controls whether to comment on Fork PRs when AllowForkPRs = False + // User config option: controls whether to comment on Fork PRs when AllowForkPRs = False SilenceForkPRErrors bool // SilenceForkPRErrorsFlag is the name of the flag that controls fork PR's. We use // this in our error message back to the user on a forked PR so they know @@ -169,7 +172,14 @@ func (c *DefaultCommandRunner) RunAutoplanCommand(baseRepo models.Repo, headRepo err = c.PreWorkflowHooksCommandRunner.RunPreHooks(ctx, cmd) if err != nil { - ctx.Log.Err("Error running pre-workflow hooks %s. Proceeding with %s command.", err, command.Plan) + ctx.Log.Err("Error running pre-workflow hooks %s.", err) + + if c.FailOnPreWorkflowHookError { + ctx.Log.Err("'fail-on-pre-workflow-hook-error' set, so not running %s command.", command.Plan) + return + } + + ctx.Log.Err("'fail-on-pre-workflow-hook-error' not set so running %s command.", command.Plan) } autoPlanRunner := buildCommentCommandRunner(c, command.Plan) @@ -293,7 +303,14 @@ func (c *DefaultCommandRunner) RunCommentCommand(baseRepo models.Repo, maybeHead err = c.PreWorkflowHooksCommandRunner.RunPreHooks(ctx, cmd) if err != nil { - ctx.Log.Err("Error running pre-workflow hooks %s. Proceeding with %s command.", err, cmd.Name.String()) + ctx.Log.Err("Error running pre-workflow hooks %s.", err) + + if c.FailOnPreWorkflowHookError { + ctx.Log.Err("'fail-on-pre-workflow-hook-error' set, so not running %s command.", cmd.Name.String()) + return + } + + ctx.Log.Err("'fail-on-pre-workflow-hook-error' not set so running %s command.", cmd.Name.String()) } cmdRunner := buildCommentCommandRunner(c, cmd.CommandName()) diff --git a/server/events/command_runner_test.go b/server/events/command_runner_test.go index 435f72b8e4..150c5f5c83 100644 --- a/server/events/command_runner_test.go +++ b/server/events/command_runner_test.go @@ -27,7 +27,7 @@ import ( "github.com/runatlantis/atlantis/server/logging" "github.com/runatlantis/atlantis/server/metrics" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" . "github.com/petergtz/pegomock/v4" lockingmocks "github.com/runatlantis/atlantis/server/core/locking/mocks" "github.com/runatlantis/atlantis/server/events" @@ -238,6 +238,7 @@ func setup(t *testing.T, options ...func(testConfig *TestConfig)) *vcsmocks.Mock VCSClient: vcsClient, CommentCommandRunnerByCmd: commentCommandRunnerByCmd, EventParser: eventParsing, + FailOnPreWorkflowHookError: false, GithubPullGetter: githubGetter, GitlabMergeRequestGetter: gitlabGetter, AzureDevopsPullGetter: azuredevopsGetter, @@ -647,6 +648,92 @@ func TestRunAutoplanCommand_DeletePlans(t *testing.T) { lockingLocker.VerifyWasCalledOnce().UnlockByPull(testdata.Pull.BaseRepo.FullName, testdata.Pull.Num) } +func TestRunAutoplanCommand_FailedPreWorkflowHook_FailOnPreWorkflowHookError_False(t *testing.T) { + setup(t) + tmp := t.TempDir() + boltDB, err := db.New(tmp) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + + When(projectCommandBuilder.BuildAutoplanCommands(Any[*command.Context]())). + ThenReturn([]command.ProjectContext{ + { + CommandName: command.Plan, + }, + }, nil) + When(projectCommandRunner.Plan(Any[command.ProjectContext]())).ThenReturn(command.ProjectResult{PlanSuccess: &models.PlanSuccess{}}) + When(workingDir.GetPullDir(Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(tmp, nil) + When(preWorkflowHooksCommandRunner.RunPreHooks(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn(errors.New("err")) + testdata.Pull.BaseRepo = testdata.GithubRepo + ch.FailOnPreWorkflowHookError = false + ch.RunAutoplanCommand(testdata.GithubRepo, testdata.GithubRepo, testdata.Pull, testdata.User) + pendingPlanFinder.VerifyWasCalledOnce().DeletePlans(tmp) + lockingLocker.VerifyWasCalledOnce().UnlockByPull(testdata.Pull.BaseRepo.FullName, testdata.Pull.Num) +} + +func TestRunAutoplanCommand_FailedPreWorkflowHook_FailOnPreWorkflowHookError_True(t *testing.T) { + setup(t) + tmp := t.TempDir() + boltDB, err := db.New(tmp) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + + When(projectCommandBuilder.BuildAutoplanCommands(Any[*command.Context]())). + ThenReturn([]command.ProjectContext{ + { + CommandName: command.Plan, + }, + }, nil) + When(preWorkflowHooksCommandRunner.RunPreHooks(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn(errors.New("err")) + testdata.Pull.BaseRepo = testdata.GithubRepo + ch.FailOnPreWorkflowHookError = true + ch.RunAutoplanCommand(testdata.GithubRepo, testdata.GithubRepo, testdata.Pull, testdata.User) + pendingPlanFinder.VerifyWasCalled(Never()).DeletePlans(Any[string]()) + lockingLocker.VerifyWasCalled(Never()).UnlockByPull(Any[string](), Any[int]()) +} + +func TestRunCommentCommand_FailedPreWorkflowHook_FailOnPreWorkflowHookError_False(t *testing.T) { + setup(t) + tmp := t.TempDir() + boltDB, err := db.New(tmp) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + + When(projectCommandRunner.Plan(Any[command.ProjectContext]())).ThenReturn(command.ProjectResult{PlanSuccess: &models.PlanSuccess{}}) + When(workingDir.GetPullDir(Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(tmp, nil) + pull := &github.PullRequest{State: github.String("open")} + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + When(githubGetter.GetPullRequest(testdata.GithubRepo, testdata.Pull.Num)).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(pull)).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + When(preWorkflowHooksCommandRunner.RunPreHooks(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn(errors.New("err")) + testdata.Pull.BaseRepo = testdata.GithubRepo + ch.FailOnPreWorkflowHookError = false + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + pendingPlanFinder.VerifyWasCalledOnce().DeletePlans(tmp) + lockingLocker.VerifyWasCalledOnce().UnlockByPull(testdata.Pull.BaseRepo.FullName, testdata.Pull.Num) +} + +func TestRunCommentCommand_FailedPreWorkflowHook_FailOnPreWorkflowHookError_True(t *testing.T) { + setup(t) + tmp := t.TempDir() + boltDB, err := db.New(tmp) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + autoMerger.GlobalAutomerge = true + defer func() { autoMerger.GlobalAutomerge = false }() + + When(preWorkflowHooksCommandRunner.RunPreHooks(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn(errors.New("err")) + testdata.Pull.BaseRepo = testdata.GithubRepo + ch.FailOnPreWorkflowHookError = true + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + pendingPlanFinder.VerifyWasCalled(Never()).DeletePlans(Any[string]()) + lockingLocker.VerifyWasCalled(Never()).UnlockByPull(Any[string](), Any[int]()) +} + func TestRunGenericPlanCommand_DeletePlans(t *testing.T) { setup(t) tmp := t.TempDir() diff --git a/server/events/delete_lock_command.go b/server/events/delete_lock_command.go index ccd7f5d146..bf66370bb7 100644 --- a/server/events/delete_lock_command.go +++ b/server/events/delete_lock_command.go @@ -53,37 +53,22 @@ func (l *DefaultDeleteLockCommand) DeleteLocksByPull(repoFullName string, pullNu return numLocks, err } if numLocks == 0 { - l.Logger.Debug("No locks found for pull") + l.Logger.Debug("No locks found for repo '%v', pull request: %v", repoFullName, pullNum) return numLocks, nil } + // The locks controller currently has no implementation of Atlantis project names, so this is hardcoded to an empty string. + projectName := "" + for i := 0; i < numLocks; i++ { lock := locks[i] - l.deleteWorkingDir(lock) - } - - return numLocks, nil -} -func (l *DefaultDeleteLockCommand) deleteWorkingDir(lock models.ProjectLock) { - // NOTE: Because BaseRepo was added to the PullRequest model later, previous - // installations of Atlantis will have locks in their DB that do not have - // this field on PullRequest. We skip deleting the working dir in this case. - if lock.Pull.BaseRepo == (models.Repo{}) { - l.Logger.Debug("Not deleting the working dir.") - return - } - unlock, err := l.WorkingDirLocker.TryLock(lock.Pull.BaseRepo.FullName, lock.Pull.Num, lock.Workspace, lock.Project.Path) - if err != nil { - l.Logger.Err("unable to obtain working dir lock when trying to delete old plans: %s", err) - } else { - defer unlock() - // nolint: vetshadow - if err := l.WorkingDir.DeleteForWorkspace(lock.Pull.BaseRepo, lock.Pull, lock.Workspace); err != nil { - l.Logger.Err("unable to delete workspace: %s", err) + err := l.WorkingDir.DeletePlan(lock.Pull.BaseRepo, lock.Pull, lock.Workspace, lock.Project.Path, projectName) + if err != nil { + l.Logger.Warn("Failed to delete plan: %s", err) + return numLocks, err } } - if err := l.Backend.UpdateProjectStatus(lock.Pull, lock.Workspace, lock.Project.Path, models.DiscardedPlanStatus); err != nil { - l.Logger.Err("unable to delete project status: %s", err) - } + + return numLocks, nil } diff --git a/server/events/delete_lock_command_test.go b/server/events/delete_lock_command_test.go index ade6e64362..87d8478337 100644 --- a/server/events/delete_lock_command_test.go +++ b/server/events/delete_lock_command_test.go @@ -113,17 +113,84 @@ func TestDeleteLocksByPull_None(t *testing.T) { workingDir.VerifyWasCalled(Never()).DeletePlan(Any[models.Repo](), Any[models.PullRequest](), Any[string](), Any[string](), Any[string]()) } -func TestDeleteLocksByPull_OldFormat(t *testing.T) { - t.Log("If the lock doesn't have BaseRepo set it is deleted successfully") +func TestDeleteLocksByPull_SingleSuccess(t *testing.T) { + t.Log("If a single lock is successfully deleted") repoName := "reponame" pullNum := 2 + path := "." + workspace := "default" + projectName := "" + RegisterMockTestingT(t) l := lockmocks.NewMockLocker() - When(l.UnlockByPull(repoName, pullNum)).ThenReturn([]models.ProjectLock{{}}, nil) + workingDir := events.NewMockWorkingDir() + pull := models.PullRequest{ + BaseRepo: models.Repo{FullName: repoName}, + Num: pullNum, + } + When(l.UnlockByPull(repoName, pullNum)).ThenReturn([]models.ProjectLock{ + { + Pull: pull, + Workspace: workspace, + Project: models.Project{ + Path: path, + RepoFullName: pull.BaseRepo.FullName, + }, + }, + }, nil, + ) dlc := events.DefaultDeleteLockCommand{ - Locker: l, - Logger: logging.NewNoopLogger(t), + Locker: l, + Logger: logging.NewNoopLogger(t), + WorkingDir: workingDir, + } + _, err := dlc.DeleteLocksByPull(repoName, pullNum) + Ok(t, err) + workingDir.VerifyWasCalled(Once()).DeletePlan(pull.BaseRepo, pull, workspace, path, projectName) +} + +func TestDeleteLocksByPull_MultipleSuccess(t *testing.T) { + t.Log("If multiple locks are successfully deleted") + repoName := "reponame" + pullNum := 2 + path1 := "path1" + path2 := "path2" + workspace := "default" + projectName := "" + + RegisterMockTestingT(t) + l := lockmocks.NewMockLocker() + workingDir := events.NewMockWorkingDir() + pull := models.PullRequest{ + BaseRepo: models.Repo{FullName: repoName}, + Num: pullNum, + } + When(l.UnlockByPull(repoName, pullNum)).ThenReturn([]models.ProjectLock{ + { + Pull: pull, + Workspace: workspace, + Project: models.Project{ + Path: path1, + RepoFullName: pull.BaseRepo.FullName, + }, + }, + { + Pull: pull, + Workspace: workspace, + Project: models.Project{ + Path: path2, + RepoFullName: pull.BaseRepo.FullName, + }, + }, + }, nil, + ) + dlc := events.DefaultDeleteLockCommand{ + Locker: l, + Logger: logging.NewNoopLogger(t), + WorkingDir: workingDir, } _, err := dlc.DeleteLocksByPull(repoName, pullNum) Ok(t, err) + workingDir.VerifyWasCalled(Once()).DeletePlan(pull.BaseRepo, pull, workspace, path1, projectName) + workingDir.VerifyWasCalled(Once()).DeletePlan(pull.BaseRepo, pull, workspace, path2, projectName) } diff --git a/server/events/event_parser.go b/server/events/event_parser.go index 1ab99938ad..379cba7bb5 100644 --- a/server/events/event_parser.go +++ b/server/events/event_parser.go @@ -21,7 +21,7 @@ import ( "strings" "github.com/go-playground/validator/v10" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" lru "github.com/hashicorp/golang-lru/v2" "github.com/mcdafydd/go-azuredevops/azuredevops" "github.com/pkg/errors" diff --git a/server/events/event_parser_test.go b/server/events/event_parser_test.go index fc7fc38917..d1ec65182a 100644 --- a/server/events/event_parser_test.go +++ b/server/events/event_parser_test.go @@ -21,7 +21,7 @@ import ( "strings" "testing" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" "github.com/mcdafydd/go-azuredevops/azuredevops" "github.com/mohae/deepcopy" "github.com/runatlantis/atlantis/server/events" diff --git a/server/events/mock_workingdir_test.go b/server/events/mock_workingdir_test.go index 046b9a2034..27a0695ea5 100644 --- a/server/events/mock_workingdir_test.go +++ b/server/events/mock_workingdir_test.go @@ -93,6 +93,25 @@ func (mock *MockWorkingDir) DeletePlan(r models.Repo, p models.PullRequest, work return ret0 } +func (mock *MockWorkingDir) GetGitUntrackedFiles(r models.Repo, p models.PullRequest, workspace string) ([]string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockWorkingDir().") + } + params := []pegomock.Param{r, p, workspace} + result := pegomock.GetGenericMockFrom(mock).Invoke("GetGitUntrackedFiles", params, []reflect.Type{reflect.TypeOf((*[]string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 []string + var ret1 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].([]string) + } + if result[1] != nil { + ret1 = result[1].(error) + } + } + return ret0, ret1 +} + func (mock *MockWorkingDir) GetPullDir(r models.Repo, p models.PullRequest) (string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWorkingDir().") @@ -335,6 +354,41 @@ func (c *MockWorkingDir_DeletePlan_OngoingVerification) GetAllCapturedArguments( return } +func (verifier *VerifierMockWorkingDir) GetGitUntrackedFiles(r models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification { + params := []pegomock.Param{r, p, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetGitUntrackedFiles", params, verifier.timeout) + return &MockWorkingDir_GetGitUntrackedFiles_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockWorkingDir_GetGitUntrackedFiles_OngoingVerification struct { + mock *MockWorkingDir + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, string) { + r, p, workspace := c.GetAllCapturedArguments() + return r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1] +} + +func (c *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []string) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(models.Repo) + } + _param1 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range params[1] { + _param1[u] = param.(models.PullRequest) + } + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range params[2] { + _param2[u] = param.(string) + } + } + return +} + func (verifier *VerifierMockWorkingDir) GetPullDir(r models.Repo, p models.PullRequest) *MockWorkingDir_GetPullDir_OngoingVerification { params := []pegomock.Param{r, p} methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullDir", params, verifier.timeout) diff --git a/server/events/mocks/mock_event_parsing.go b/server/events/mocks/mock_event_parsing.go index ef45393891..0f7067eb89 100644 --- a/server/events/mocks/mock_event_parsing.go +++ b/server/events/mocks/mock_event_parsing.go @@ -4,7 +4,7 @@ package mocks import ( - github "github.com/google/go-github/v53/github" + github "github.com/google/go-github/v54/github" azuredevops "github.com/mcdafydd/go-azuredevops/azuredevops" pegomock "github.com/petergtz/pegomock/v4" models "github.com/runatlantis/atlantis/server/events/models" diff --git a/server/events/mocks/mock_github_pull_getter.go b/server/events/mocks/mock_github_pull_getter.go index 8a0201d43f..f2247cc473 100644 --- a/server/events/mocks/mock_github_pull_getter.go +++ b/server/events/mocks/mock_github_pull_getter.go @@ -4,7 +4,7 @@ package mocks import ( - github "github.com/google/go-github/v53/github" + github "github.com/google/go-github/v54/github" pegomock "github.com/petergtz/pegomock/v4" models "github.com/runatlantis/atlantis/server/events/models" "reflect" diff --git a/server/events/mocks/mock_working_dir.go b/server/events/mocks/mock_working_dir.go index e22c2ee921..8f051f1937 100644 --- a/server/events/mocks/mock_working_dir.go +++ b/server/events/mocks/mock_working_dir.go @@ -93,6 +93,25 @@ func (mock *MockWorkingDir) DeletePlan(r models.Repo, p models.PullRequest, work return ret0 } +func (mock *MockWorkingDir) GetGitUntrackedFiles(r models.Repo, p models.PullRequest, workspace string) ([]string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockWorkingDir().") + } + params := []pegomock.Param{r, p, workspace} + result := pegomock.GetGenericMockFrom(mock).Invoke("GetGitUntrackedFiles", params, []reflect.Type{reflect.TypeOf((*[]string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 []string + var ret1 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].([]string) + } + if result[1] != nil { + ret1 = result[1].(error) + } + } + return ret0, ret1 +} + func (mock *MockWorkingDir) GetPullDir(r models.Repo, p models.PullRequest) (string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWorkingDir().") @@ -335,6 +354,41 @@ func (c *MockWorkingDir_DeletePlan_OngoingVerification) GetAllCapturedArguments( return } +func (verifier *VerifierMockWorkingDir) GetGitUntrackedFiles(r models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification { + params := []pegomock.Param{r, p, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetGitUntrackedFiles", params, verifier.timeout) + return &MockWorkingDir_GetGitUntrackedFiles_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockWorkingDir_GetGitUntrackedFiles_OngoingVerification struct { + mock *MockWorkingDir + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, string) { + r, p, workspace := c.GetAllCapturedArguments() + return r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1] +} + +func (c *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []string) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(models.Repo) + } + _param1 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range params[1] { + _param1[u] = param.(models.PullRequest) + } + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range params[2] { + _param2[u] = param.(string) + } + } + return +} + func (verifier *VerifierMockWorkingDir) GetPullDir(r models.Repo, p models.PullRequest) *MockWorkingDir_GetPullDir_OngoingVerification { params := []pegomock.Param{r, p} methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullDir", params, verifier.timeout) diff --git a/server/events/plan_command_runner_test.go b/server/events/plan_command_runner_test.go index 80ed066d7f..e765f434c5 100644 --- a/server/events/plan_command_runner_test.go +++ b/server/events/plan_command_runner_test.go @@ -4,7 +4,7 @@ import ( "errors" "testing" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" . "github.com/petergtz/pegomock/v4" "github.com/runatlantis/atlantis/server/core/db" "github.com/runatlantis/atlantis/server/events" diff --git a/server/events/project_command_builder.go b/server/events/project_command_builder.go index d33ee8a8db..c7b3b064d9 100644 --- a/server/events/project_command_builder.go +++ b/server/events/project_command_builder.go @@ -53,6 +53,7 @@ func NewInstrumentedProjectCommandBuilder( AutoplanFileList string, RestrictFileList bool, SilenceNoProjects bool, + IncludeGitUntrackedFiles bool, scope tally.Scope, logger logging.SimpleLogging, terraformClient terraform.Client, @@ -83,6 +84,7 @@ func NewInstrumentedProjectCommandBuilder( AutoplanFileList, RestrictFileList, SilenceNoProjects, + IncludeGitUntrackedFiles, scope, logger, terraformClient, @@ -111,27 +113,29 @@ func NewProjectCommandBuilder( AutoplanFileList string, RestrictFileList bool, SilenceNoProjects bool, + IncludeGitUntrackedFiles bool, scope tally.Scope, logger logging.SimpleLogging, terraformClient terraform.Client, ) *DefaultProjectCommandBuilder { return &DefaultProjectCommandBuilder{ - ParserValidator: parserValidator, - ProjectFinder: projectFinder, - VCSClient: vcsClient, - WorkingDir: workingDir, - WorkingDirLocker: workingDirLocker, - GlobalCfg: globalCfg, - PendingPlanFinder: pendingPlanFinder, - SkipCloneNoChanges: skipCloneNoChanges, - EnableRegExpCmd: EnableRegExpCmd, - EnableAutoMerge: EnableAutoMerge, - EnableParallelPlan: EnableParallelPlan, - EnableParallelApply: EnableParallelApply, - AutoDetectModuleFiles: AutoDetectModuleFiles, - AutoplanFileList: AutoplanFileList, - RestrictFileList: RestrictFileList, - SilenceNoProjects: SilenceNoProjects, + ParserValidator: parserValidator, + ProjectFinder: projectFinder, + VCSClient: vcsClient, + WorkingDir: workingDir, + WorkingDirLocker: workingDirLocker, + GlobalCfg: globalCfg, + PendingPlanFinder: pendingPlanFinder, + SkipCloneNoChanges: skipCloneNoChanges, + EnableRegExpCmd: EnableRegExpCmd, + EnableAutoMerge: EnableAutoMerge, + EnableParallelPlan: EnableParallelPlan, + EnableParallelApply: EnableParallelApply, + AutoDetectModuleFiles: AutoDetectModuleFiles, + AutoplanFileList: AutoplanFileList, + RestrictFileList: RestrictFileList, + SilenceNoProjects: SilenceNoProjects, + IncludeGitUntrackedFiles: IncludeGitUntrackedFiles, ProjectCommandContextBuilder: NewProjectCommandContextBuilder( policyChecksSupported, commentBuilder, @@ -184,7 +188,7 @@ type ProjectStateCommandBuilder interface { BuildStateRmCommands(ctx *command.Context, comment *CommentCommand) ([]command.ProjectContext, error) } -//go:generate pegomock generate --package mocks -o mocks/mock_project_command_builder.go ProjectCommandBuilder +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_project_command_builder.go ProjectCommandBuilder // ProjectCommandBuilder builds commands that run on individual projects. type ProjectCommandBuilder interface { @@ -200,25 +204,46 @@ type ProjectCommandBuilder interface { // This class combines the data from the comment and any atlantis.yaml file or // Atlantis server config and then generates a set of contexts. type DefaultProjectCommandBuilder struct { - ParserValidator *config.ParserValidator - ProjectFinder ProjectFinder - VCSClient vcs.Client - WorkingDir WorkingDir - WorkingDirLocker WorkingDirLocker - GlobalCfg valid.GlobalCfg - PendingPlanFinder *DefaultPendingPlanFinder + // Parses and validates server-side repo config files and repo-level atlantis.yaml files. + ParserValidator *config.ParserValidator + // Determines which projects were modified in a given pull request. + ProjectFinder ProjectFinder + // Used to make API calls to a VCS host like GitHub or GitLab. + VCSClient vcs.Client + // Handles the workspace on disk for running commands. + WorkingDir WorkingDir + // Used to prevent multiple commands from executing at the same time for a single repo, pull, and workspace. + WorkingDirLocker WorkingDirLocker + // The final parsed version of the server-side repo config. + GlobalCfg valid.GlobalCfg + // Finds unapplied plans. + PendingPlanFinder *DefaultPendingPlanFinder + // Builds project command contexts for Atlantis commands. ProjectCommandContextBuilder ProjectCommandContextBuilder - SkipCloneNoChanges bool - EnableRegExpCmd bool - EnableAutoMerge bool - EnableParallelPlan bool - EnableParallelApply bool - AutoDetectModuleFiles string - AutoplanFileList string - EnableDiffMarkdownFormat bool - RestrictFileList bool - SilenceNoProjects bool - TerraformExecutor terraform.Client + // User config option: Skip cloning the repo during autoplan if there are no changes to Terraform projects. + SkipCloneNoChanges bool + // User config option: Enable the use of regular expressions to run plan/apply commands against defined project names. + EnableRegExpCmd bool + // User config option: Automatically merge pull requests after all plans have been successfully applied. + EnableAutoMerge bool + // User config option: Whether to run plan operations in parallel. + EnableParallelPlan bool + // User config option: Whether to run apply operations in parallel. + EnableParallelApply bool + // User config option: Enables auto-planning of projects when a module dependency in the same repository has changed. + AutoDetectModuleFiles string + // User config option: List of file patterns to to to check if a directory contains modified files. + AutoplanFileList string + // User config option: Format Terraform plan output into a markdown-diff friendy format for color-coding purposes. + EnableDiffMarkdownFormat bool + // User config option: Block plan requests from projects outside the files modified in the pull request. + RestrictFileList bool + // User config option: Ignore PR if none of the modified files are part of a project. + SilenceNoProjects bool + // User config option: Include git untracked files in the modified file list. + IncludeGitUntrackedFiles bool + // Handles the actual running of Terraform commands. + TerraformExecutor terraform.Client } // See ProjectCommandBuilder.BuildAutoplanCommands. @@ -241,8 +266,11 @@ func (p *DefaultProjectCommandBuilder) BuildAutoplanCommands(ctx *command.Contex // See ProjectCommandBuilder.BuildPlanCommands. func (p *DefaultProjectCommandBuilder) BuildPlanCommands(ctx *command.Context, cmd *CommentCommand) ([]command.ProjectContext, error) { if !cmd.IsForSpecificProject() { + ctx.Log.Debug("Building plan command for all affected projects") return p.buildAllCommandsByCfg(ctx, cmd.CommandName(), cmd.SubName, cmd.Flags, cmd.Verbose) } + ctx.Log.Debug("Building plan command for specific project with directory: '%v', workspace: '%v', project: '%v'", + cmd.RepoRelDir, cmd.Workspace, cmd.ProjectName) pcc, err := p.buildProjectPlanCommand(ctx, cmd) return pcc, err } @@ -296,7 +324,17 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex if err != nil { return nil, err } - ctx.Log.Debug("%d files were modified in this pull request", len(modifiedFiles)) + + if p.IncludeGitUntrackedFiles { + ctx.Log.Debug(("'include-git-untracked-files' option is set, getting untracked files")) + untrackedFiles, err := p.WorkingDir.GetGitUntrackedFiles(ctx.HeadRepo, ctx.Pull, DefaultWorkspace) + if err != nil { + return nil, err + } + modifiedFiles = append(modifiedFiles, untrackedFiles...) + } + + ctx.Log.Debug("%d files were modified in this pull request. Modified files: %v", len(modifiedFiles), modifiedFiles) if p.SkipCloneNoChanges && p.VCSClient.SupportsSingleFileDownload(ctx.Pull.BaseRepo) { repoCfgFile := p.GlobalCfg.RepoConfigFile(ctx.Pull.BaseRepo.ID()) @@ -479,12 +517,25 @@ func (p *DefaultProjectCommandBuilder) buildProjectPlanCommand(ctx *command.Cont } if p.RestrictFileList { + ctx.Log.Debug("'restrict-file-list' option is set, checking modified files") modifiedFiles, err := p.VCSClient.GetModifiedFiles(ctx.Pull.BaseRepo, ctx.Pull) if err != nil { return nil, err } + if p.IncludeGitUntrackedFiles { + ctx.Log.Debug(("'include-git-untracked-files' option is set, getting untracked files")) + untrackedFiles, err := p.WorkingDir.GetGitUntrackedFiles(ctx.HeadRepo, ctx.Pull, workspace) + if err != nil { + return nil, err + } + modifiedFiles = append(modifiedFiles, untrackedFiles...) + } + + ctx.Log.Debug("%d files were modified in this pull request. Modified files: %v", len(modifiedFiles), modifiedFiles) + if cmd.RepoRelDir != "" { + ctx.Log.Debug("Command directory specified: %s", cmd.RepoRelDir) foundDir := false for _, f := range modifiedFiles { @@ -499,6 +550,7 @@ func (p *DefaultProjectCommandBuilder) buildProjectPlanCommand(ctx *command.Cont } if cmd.ProjectName != "" { + ctx.Log.Debug("Command project name specified: %s", cmd.ProjectName) var notFoundFiles = []string{} var repoConfig valid.RepoCfg diff --git a/server/events/project_command_builder_internal_test.go b/server/events/project_command_builder_internal_test.go index b0a4c8760d..e8804c5142 100644 --- a/server/events/project_command_builder_internal_test.go +++ b/server/events/project_command_builder_internal_test.go @@ -672,6 +672,7 @@ projects: "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, false, + false, statsScope, logger, terraformClient, @@ -886,6 +887,7 @@ projects: "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, false, + false, statsScope, logger, terraformClient, @@ -1134,6 +1136,7 @@ workflows: "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, false, + false, statsScope, logger, terraformClient, @@ -1289,6 +1292,7 @@ projects: "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, true, + false, statsScope, logger, terraformClient, diff --git a/server/events/project_command_builder_test.go b/server/events/project_command_builder_test.go index 36ed6426a0..6a3e73798d 100644 --- a/server/events/project_command_builder_test.go +++ b/server/events/project_command_builder_test.go @@ -22,6 +22,30 @@ import ( . "github.com/runatlantis/atlantis/testing" ) +var defaultUserConfig = struct { + SkipCloneNoChanges bool + EnableRegExpCmd bool + EnableAutoMerge bool + EnableParallelPlan bool + EnableParallelApply bool + AutoDetectModuleFiles string + AutoplanFileList string + RestrictFileList bool + SilenceNoProjects bool + IncludeGitUntrackedFiles bool +}{ + SkipCloneNoChanges: false, + EnableRegExpCmd: false, + EnableAutoMerge: false, + EnableParallelPlan: false, + EnableParallelApply: false, + AutoDetectModuleFiles: "", + AutoplanFileList: "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", + RestrictFileList: false, + SilenceNoProjects: false, + IncludeGitUntrackedFiles: true, +} + func TestDefaultProjectCommandBuilder_BuildAutoplanCommands(t *testing.T) { // expCtxFields define the ctx fields we're going to assert on. // Since we're focused on autoplanning here, we don't validate all the @@ -122,6 +146,7 @@ projects: logger := logging.NewNoopLogger(t) scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig terraformClient := terraform_mocks.NewMockClient() When(terraformClient.ListAvailableVersions(Any[logging.SimpleLogging]())).ThenReturn([]string{}, nil) @@ -159,15 +184,16 @@ projects: valid.NewGlobalCfgFromArgs(globalCfgArgs), &events.DefaultPendingPlanFinder{}, &events.CommentParser{ExecutableName: "atlantis"}, - false, - false, - false, - false, - false, - "", - "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", - false, - false, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, scope, logger, terraformClient, @@ -473,6 +499,7 @@ projects: logger := logging.NewNoopLogger(t) scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig for _, c := range cases { // NOTE: we're testing both plan and apply here. @@ -513,15 +540,16 @@ projects: valid.NewGlobalCfgFromArgs(globalCfgArgs), &events.DefaultPendingPlanFinder{}, &events.CommentParser{ExecutableName: "atlantis"}, - false, - true, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, c.EnableAutoMergeUserCfg, c.EnableParallelPlanUserCfg, c.EnableParallelApplyUserCfg, - "", - "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", - false, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, c.Silenced, + userConfig.IncludeGitUntrackedFiles, scope, logger, terraformClient, @@ -663,6 +691,8 @@ projects: logger := logging.NewNoopLogger(t) scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + userConfig.RestrictFileList = true for _, c := range cases { t.Run(c.Description+"_"+command.Plan.String(), func(t *testing.T) { @@ -699,15 +729,16 @@ projects: valid.NewGlobalCfgFromArgs(globalCfgArgs), &events.DefaultPendingPlanFinder{}, &events.CommentParser{ExecutableName: "atlantis"}, - false, - true, - false, - false, - false, - "", - "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", - true, - false, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, scope, logger, terraformClient, @@ -929,6 +960,8 @@ projects: logger := logging.NewNoopLogger(t) scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + for name, c := range cases { t.Run(name, func(t *testing.T) { RegisterMockTestingT(t) @@ -964,15 +997,16 @@ projects: valid.NewGlobalCfgFromArgs(globalCfgArgs), &events.DefaultPendingPlanFinder{}, &events.CommentParser{ExecutableName: "atlantis"}, - false, - false, - false, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, c.ParallelPlanEnabledUserCfg, c.ParallelApplyEnabledUserCfg, - "", - "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", - false, - false, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, scope, logger, terraformClient, @@ -1044,6 +1078,7 @@ func TestDefaultProjectCommandBuilder_BuildMultiApply(t *testing.T) { ThenReturn(tmpDir, nil) logger := logging.NewNoopLogger(t) + userConfig := defaultUserConfig globalCfgArgs := valid.GlobalCfgArgs{ AllowRepoCfg: false, @@ -1066,15 +1101,16 @@ func TestDefaultProjectCommandBuilder_BuildMultiApply(t *testing.T) { valid.NewGlobalCfgFromArgs(globalCfgArgs), &events.DefaultPendingPlanFinder{}, &events.CommentParser{ExecutableName: "atlantis"}, - false, - false, - false, - false, - false, - "", - "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", - false, - false, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, scope, logger, terraformClient, @@ -1145,6 +1181,8 @@ projects: } logger := logging.NewNoopLogger(t) scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + terraformClient := terraform_mocks.NewMockClient() When(terraformClient.ListAvailableVersions(Any[logging.SimpleLogging]())).ThenReturn([]string{}, nil) @@ -1158,15 +1196,16 @@ projects: valid.NewGlobalCfgFromArgs(globalCfgArgs), &events.DefaultPendingPlanFinder{}, &events.CommentParser{ExecutableName: "atlantis"}, - false, - false, - false, - false, - false, - "", - "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", - false, - false, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, scope, logger, terraformClient, @@ -1212,6 +1251,7 @@ func TestDefaultProjectCommandBuilder_EscapeArgs(t *testing.T) { logger := logging.NewNoopLogger(t) scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig for _, c := range cases { t.Run(strings.Join(c.ExtraArgs, " "), func(t *testing.T) { @@ -1246,15 +1286,16 @@ func TestDefaultProjectCommandBuilder_EscapeArgs(t *testing.T) { valid.NewGlobalCfgFromArgs(globalCfgArgs), &events.DefaultPendingPlanFinder{}, &events.CommentParser{ExecutableName: "atlantis"}, - false, - false, - false, - false, - false, - "", - "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", - false, - false, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, scope, logger, terraformClient, @@ -1366,6 +1407,7 @@ projects: logger := logging.NewNoopLogger(t) scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig for name, testCase := range testCases { t.Run(name, func(t *testing.T) { @@ -1415,15 +1457,16 @@ projects: valid.NewGlobalCfgFromArgs(globalCfgArgs), &events.DefaultPendingPlanFinder{}, &events.CommentParser{ExecutableName: "atlantis"}, - false, - false, - false, - false, - false, - "", - "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", - false, - false, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, scope, logger, terraformClient, @@ -1482,6 +1525,9 @@ parallel_plan: true`, }, } + userConfig := defaultUserConfig + userConfig.SkipCloneNoChanges = true + for _, c := range cases { RegisterMockTestingT(t) vcsClient := vcsmocks.NewMockClient() @@ -1512,15 +1558,16 @@ parallel_plan: true`, valid.NewGlobalCfgFromArgs(globalCfgArgs), &events.DefaultPendingPlanFinder{}, &events.CommentParser{ExecutableName: "atlantis"}, - true, - false, - false, - false, - false, - "", - "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", - false, - false, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, scope, logger, terraformClient, @@ -1552,6 +1599,7 @@ func TestDefaultProjectCommandBuilder_WithPolicyCheckEnabled_BuildAutoplanComman logger := logging.NewNoopLogger(t) scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig workingDir := mocks.NewMockWorkingDir() When(workingDir.Clone(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, false, nil) @@ -1580,15 +1628,16 @@ func TestDefaultProjectCommandBuilder_WithPolicyCheckEnabled_BuildAutoplanComman globalCfg, &events.DefaultPendingPlanFinder{}, &events.CommentParser{ExecutableName: "atlantis"}, - false, - false, - false, - false, - false, - "", - "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", - false, - false, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, scope, logger, terraformClient, @@ -1650,6 +1699,7 @@ func TestDefaultProjectCommandBuilder_BuildVersionCommand(t *testing.T) { logger := logging.NewNoopLogger(t) scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig globalCfgArgs := valid.GlobalCfgArgs{ AllowRepoCfg: false, @@ -1670,15 +1720,16 @@ func TestDefaultProjectCommandBuilder_BuildVersionCommand(t *testing.T) { valid.NewGlobalCfgFromArgs(globalCfgArgs), &events.DefaultPendingPlanFinder{}, &events.CommentParser{ExecutableName: "atlantis"}, - false, - false, - false, - false, - false, - "", - "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", - false, - false, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, scope, logger, terraformClient, @@ -1708,3 +1759,238 @@ func TestDefaultProjectCommandBuilder_BuildVersionCommand(t *testing.T) { Equals(t, "project2", ctxs[3].RepoRelDir) Equals(t, "workspace2", ctxs[3].Workspace) } + +// Test +func TestDefaultProjectCommandBuilder_BuildPlanCommands_Single_With_RestrictFileList_And_IncludeGitUntrackedFiles(t *testing.T) { + testDir1 := "directory-1" + testDir2 := "directory-2" + + cases := []struct { + Description string + AtlantisYAML string + DirectoryStructure map[string]interface{} + ModifiedFiles []string + UntrackedFiles []string + Cmd events.CommentCommand + ExpRepoRelDir string + ExpErr string + }{ + { + Description: "planning a git untracked file project in a modified directory", + Cmd: events.CommentCommand{ + Name: command.Plan, + RepoRelDir: testDir1 + "/ci-cdktf.out/stacks/test", + Workspace: "default", + }, + DirectoryStructure: map[string]interface{}{ + testDir1: map[string]interface{}{ + "main.ts": nil, + }, + }, + ModifiedFiles: []string{testDir1 + "/main.ts"}, + UntrackedFiles: []string{testDir1 + "/ci-cdktf.out/stacks/test/cdk.tf.json"}, + ExpRepoRelDir: testDir1 + "/ci-cdktf.out/stacks/test", + }, + { + Description: "planning a git untracked file project outside a modified directory", + Cmd: events.CommentCommand{ + Name: command.Plan, + RepoRelDir: testDir2 + "/ci-cdktf.out/stacks/test", + Workspace: "default", + }, + DirectoryStructure: map[string]interface{}{ + testDir1: map[string]interface{}{ + "main.ts": nil, + }, + }, + ModifiedFiles: []string{testDir1 + "/main.ts"}, + UntrackedFiles: []string{testDir1 + "/ci-cdktf.out/stacks/test/cdk.tf.json"}, + ExpErr: "the dir \"" + testDir2 + "/ci-cdktf.out/stacks/test\" is not in the plan list of this pull request", + }, + } + + globalCfgArgs := valid.GlobalCfgArgs{ + AllowRepoCfg: true, + MergeableReq: false, + ApprovedReq: false, + UnDivergedReq: false, + } + + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + userConfig.RestrictFileList = true + userConfig.IncludeGitUntrackedFiles = true + + for _, c := range cases { + t.Run(c.Description+"_"+command.Plan.String(), func(t *testing.T) { + RegisterMockTestingT(t) + tmpDir := DirStructure(t, c.DirectoryStructure) + + workingDir := mocks.NewMockWorkingDir() + When(workingDir.Clone(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, false, nil) + When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil) + When(workingDir.GetGitUntrackedFiles(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(c.UntrackedFiles, nil) + vcsClient := vcsmocks.NewMockClient() + When(vcsClient.GetModifiedFiles(Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(c.ModifiedFiles, nil) + if c.AtlantisYAML != "" { + err := os.WriteFile(filepath.Join(tmpDir, valid.DefaultAtlantisFile), []byte(c.AtlantisYAML), 0600) + Ok(t, err) + } + + terraformClient := terraform_mocks.NewMockClient() + When(terraformClient.ListAvailableVersions(Any[logging.SimpleLogging]())).ThenReturn([]string{}, nil) + + builder := events.NewProjectCommandBuilder( + false, // policyChecksSupported + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + vcsClient, + workingDir, + events.NewDefaultWorkingDirLocker(), + valid.NewGlobalCfgFromArgs(globalCfgArgs), + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, + scope, + logger, + terraformClient, + ) + + var actCtxs []command.ProjectContext + var err error + actCtxs, err = builder.BuildPlanCommands(&command.Context{ + Log: logger, + Scope: scope, + }, &c.Cmd) + if c.ExpErr != "" { + ErrEquals(t, c.ExpErr, err) + return + } + Ok(t, err) + Equals(t, 1, len(actCtxs)) + actCtx := actCtxs[0] + Equals(t, c.ExpRepoRelDir, actCtx.RepoRelDir) + }) + } +} + +func TestDefaultProjectCommandBuilder_BuildPlanCommands_with_IncludeGitUntrackedFiles(t *testing.T) { + testDir1 := "directory-1" + + cases := []struct { + Description string + AtlantisYAML string + DirectoryStructure map[string]interface{} + ModifiedFiles []string + UntrackedFiles []string + Cmd events.CommentCommand + ExpRepoRelDir string + ExpErr string + }{ + { + Description: "planning with a git untracked file", + Cmd: events.CommentCommand{ + Name: command.Plan, + }, + DirectoryStructure: map[string]interface{}{ + testDir1: map[string]interface{}{ + "main.ts": nil, + "ci-cdktf.out": map[string]interface{}{ + "stacks": map[string]interface{}{ + "test": map[string]interface{}{ + "cdk.tf.json": nil, + }, + }, + }, + }, + }, + ModifiedFiles: []string{testDir1 + "/main.ts"}, + UntrackedFiles: []string{testDir1 + "/ci-cdktf.out/stacks/test/cdk.tf.json"}, + ExpRepoRelDir: testDir1 + "/ci-cdktf.out/stacks/test", + }, + } + + globalCfgArgs := valid.GlobalCfgArgs{ + AllowRepoCfg: true, + MergeableReq: false, + ApprovedReq: false, + UnDivergedReq: false, + } + + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + userConfig.IncludeGitUntrackedFiles = true + userConfig.AutoplanFileList = "**/cdk.tf.json" + + for _, c := range cases { + t.Run(c.Description+"_"+command.Plan.String(), func(t *testing.T) { + RegisterMockTestingT(t) + tmpDir := DirStructure(t, c.DirectoryStructure) + + workingDir := mocks.NewMockWorkingDir() + When(workingDir.Clone(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, false, nil) + When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil) + When(workingDir.GetGitUntrackedFiles(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(c.UntrackedFiles, nil) + vcsClient := vcsmocks.NewMockClient() + When(vcsClient.GetModifiedFiles(Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(c.ModifiedFiles, nil) + if c.AtlantisYAML != "" { + err := os.WriteFile(filepath.Join(tmpDir, valid.DefaultAtlantisFile), []byte(c.AtlantisYAML), 0600) + Ok(t, err) + } + + terraformClient := terraform_mocks.NewMockClient() + When(terraformClient.ListAvailableVersions(Any[logging.SimpleLogging]())).ThenReturn([]string{}, nil) + + builder := events.NewProjectCommandBuilder( + false, // policyChecksSupported + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + vcsClient, + workingDir, + events.NewDefaultWorkingDirLocker(), + valid.NewGlobalCfgFromArgs(globalCfgArgs), + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, + scope, + logger, + terraformClient, + ) + + var actCtxs []command.ProjectContext + var err error + actCtxs, err = builder.BuildPlanCommands(&command.Context{ + Log: logger, + Scope: scope, + }, &c.Cmd) + if c.ExpErr != "" { + ErrEquals(t, c.ExpErr, err) + return + } + Ok(t, err) + Equals(t, 1, len(actCtxs)) + actCtx := actCtxs[0] + Equals(t, c.ExpRepoRelDir, actCtx.RepoRelDir) + }) + } +} diff --git a/server/events/project_command_runner_test.go b/server/events/project_command_runner_test.go index d0438daba4..a2b48ed8ef 100644 --- a/server/events/project_command_runner_test.go +++ b/server/events/project_command_runner_test.go @@ -274,7 +274,7 @@ func TestDefaultProjectCommandRunner_ApplyNotApproved(t *testing.T) { When(mockWorkingDir.GetWorkingDir(ctx.BaseRepo, ctx.Pull, ctx.Workspace)).ThenReturn(tmp, nil) res := runner.Apply(ctx) - Equals(t, "Pull request must be approved by at least one person other than the author before running apply.", res.Failure) + Equals(t, "Pull request must be approved according to the project's approval rules before running apply.", res.Failure) } // Test that if mergeable is required and the PR isn't mergeable we give an error. @@ -678,7 +678,7 @@ func TestDefaultProjectCommandRunner_Import(t *testing.T) { IsApproved: false, }, }, - expFailure: "Pull request must be approved by at least one person other than the author before running import.", + expFailure: "Pull request must be approved according to the project's approval rules before running import.", }, } diff --git a/server/events/project_finder.go b/server/events/project_finder.go index 661495faf6..0321701b45 100644 --- a/server/events/project_finder.go +++ b/server/events/project_finder.go @@ -144,7 +144,7 @@ func (p *DefaultProjectFinder) DetermineProjects(log logging.SimpleLogging, modi if len(modifiedTerraformFiles) == 0 { return projects } - log.Info("filtered modified files to %d .tf or terragrunt.hcl files: %v", + log.Info("filtered modified files to %d file(s) in the autoplan file list: %v", len(modifiedTerraformFiles), modifiedTerraformFiles) var dirs []string diff --git a/server/events/unlock_command_runner.go b/server/events/unlock_command_runner.go index 1a7407397d..012da284ee 100644 --- a/server/events/unlock_command_runner.go +++ b/server/events/unlock_command_runner.go @@ -32,6 +32,7 @@ func (u *UnlockCommandRunner) Run( baseRepo := ctx.Pull.BaseRepo pullNum := ctx.Pull.Num + ctx.Log.Info("Unlocking all locks") vcsMessage := "All Atlantis locks for this PR have been unlocked and plans discarded" numLocks, err := u.deleteLockCommand.DeleteLocksByPull(baseRepo.FullName, pullNum) if err != nil { @@ -40,8 +41,11 @@ func (u *UnlockCommandRunner) Run( } // if there are no locks to delete, no errors, and SilenceNoProjects is enabled, don't comment - if err == nil && numLocks == 0 && u.SilenceNoProjects { - return + if err == nil && numLocks == 0 { + ctx.Log.Info("No locks to delete") + if u.SilenceNoProjects { + return + } } if commentErr := u.vcsClient.CreateComment(baseRepo, pullNum, vcsMessage, command.Unlock.String()); commentErr != nil { diff --git a/server/events/vcs/github_client.go b/server/events/vcs/github_client.go index aa64dc8cbc..608deda5d7 100644 --- a/server/events/vcs/github_client.go +++ b/server/events/vcs/github_client.go @@ -21,7 +21,7 @@ import ( "strings" "time" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" "github.com/pkg/errors" "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" @@ -418,6 +418,10 @@ func (g *GithubClient) GetCombinedStatusMinusApply(repo models.Repo, pull *githu return false, errors.Wrap(err, "getting required status checks") } + if required.RequiredStatusChecks == nil { + return true, nil + } + //check check suite/check run api checksuites, _, err := g.client.Checks.ListCheckSuitesForRef(context.Background(), *pull.Head.Repo.Owner.Login, repo.Name, *pull.Head.Ref, nil) if err != nil { diff --git a/server/events/vcs/github_client_test.go b/server/events/vcs/github_client_test.go index b84de928df..e42e353027 100644 --- a/server/events/vcs/github_client_test.go +++ b/server/events/vcs/github_client_test.go @@ -737,6 +737,114 @@ func TestGithubClient_PullIsMergeableWithAllowMergeableBypassApply(t *testing.T) } } +func TestGithubClient_PullIsMergeableWithAllowMergeableBypassApplyButWithNoBranchProtectionChecks(t *testing.T) { + vcsStatusName := "atlantis" + cases := []struct { + state string + reviewDecision string + expMergeable bool + }{ + { + "blocked", + `"REVIEW_REQUIRED"`, + false, + }, + } + + // Use a real GitHub json response and edit the mergeable_state field. + jsBytes, err := os.ReadFile("testdata/github-pull-request.json") + Ok(t, err) + prJSON := string(jsBytes) + + // Status Check Response + jsBytes, err = os.ReadFile("testdata/github-commit-status-full.json") + Ok(t, err) + commitJSON := string(jsBytes) + + // Branch protection Response + jsBytes, err = os.ReadFile("testdata/github-branch-protection-no-required-checks.json") + Ok(t, err) + branchProtectionJSON := string(jsBytes) + + // List check suites Response + jsBytes, err = os.ReadFile("testdata/github-commit-check-suites-completed.json") + Ok(t, err) + checkSuites := string(jsBytes) + + // List check runs in a check suite + jsBytes, err = os.ReadFile("testdata/github-commit-check-suites-check-runs-completed.json") + Ok(t, err) + checkRuns := string(jsBytes) + + for _, c := range cases { + t.Run(c.state, func(t *testing.T) { + response := strings.Replace(prJSON, + `"mergeable_state": "clean"`, + fmt.Sprintf(`"mergeable_state": "%s"`, c.state), + 1, + ) + + // reviewDecision Response + reviewDecision := fmt.Sprintf(`{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": %s + } + } + } + }`, c.reviewDecision) + + testServer := httptest.NewTLSServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v3/repos/octocat/Hello-World/pulls/1": + w.Write([]byte(response)) // nolint: errcheck + return + case "/api/v3/repos/octocat/Hello-World/pulls/1/reviews?per_page=300": + w.Write([]byte("[]")) // nolint: errcheck + return + case "/api/v3/repos/octocat/Hello-World/commits/new-topic/status": + w.Write([]byte(commitJSON)) // nolint: errcheck + case "/api/graphql": + w.Write([]byte(reviewDecision)) // nolint: errcheck + case "/api/v3/repos/octocat/Hello-World/branches/main/protection": + w.Write([]byte(branchProtectionJSON)) // nolint: errcheck + case "/api/v3/repos/octocat/Hello-World/commits/new-topic/check-suites": + w.Write([]byte(checkSuites)) // nolint: errcheck + case "/api/v3/repos/octocat/Hello-World/check-suites/1234567890/check-runs": + w.Write([]byte(checkRuns)) // nolint: errcheck + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + })) + testServerURL, err := url.Parse(testServer.URL) + Ok(t, err) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{AllowMergeableBypassApply: true}, logging.NewNoopLogger(t)) + Ok(t, err) + defer disableSSLVerification()() + + actMergeable, err := client.PullIsMergeable(models.Repo{ + FullName: "octocat/Hello-World", + Owner: "octocat", + Name: "Hello-World", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.Github, + Hostname: "github.com", + }, + }, models.PullRequest{ + Num: 1, + }, vcsStatusName) + Ok(t, err) + Equals(t, c.expMergeable, actMergeable) + }) + } +} + func TestGithubClient_MergePullHandlesError(t *testing.T) { cases := []struct { code int diff --git a/server/events/vcs/github_credentials.go b/server/events/vcs/github_credentials.go index d2f5771a4b..1d5a92c117 100644 --- a/server/events/vcs/github_credentials.go +++ b/server/events/vcs/github_credentials.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/bradleyfalzon/ghinstallation/v2" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" "github.com/pkg/errors" ) diff --git a/server/events/vcs/gitlab_client.go b/server/events/vcs/gitlab_client.go index f96d964fda..030629c8b8 100644 --- a/server/events/vcs/gitlab_client.go +++ b/server/events/vcs/gitlab_client.go @@ -283,7 +283,7 @@ func (g *GitlabClient) PullIsMergeable(repo models.Repo, pull models.PullRequest // Prevent nil pointer error when mr.HeadPipeline is empty // See: https://github.com/runatlantis/atlantis/issues/1852 commit := pull.HeadCommit - isPipelineSkipped := true + isPipelineSkipped := false if mr.HeadPipeline != nil { commit = mr.HeadPipeline.SHA isPipelineSkipped = mr.HeadPipeline.Status == "skipped" diff --git a/server/events/vcs/gitlab_client_test.go b/server/events/vcs/gitlab_client_test.go index 5d4e6a701b..a7f1a77be6 100644 --- a/server/events/vcs/gitlab_client_test.go +++ b/server/events/vcs/gitlab_client_test.go @@ -367,6 +367,27 @@ func TestGitlabClient_PullIsMergeable(t *testing.T) { defaultMr, true, }, + { + fmt.Sprintf("%s/apply: resource/default", vcsStatusName), + models.FailedCommitStatus, + gitlabServerVersions, + noHeadPipelineMR, + true, + }, + { + fmt.Sprintf("%s/apply", vcsStatusName), + models.FailedCommitStatus, + gitlabServerVersions, + noHeadPipelineMR, + true, + }, + { + fmt.Sprintf("%s/plan: resource/default", vcsStatusName), + models.FailedCommitStatus, + gitlabServerVersions, + noHeadPipelineMR, + false, + }, { fmt.Sprintf("%s/plan", vcsStatusName), models.PendingCommitStatus, @@ -381,6 +402,13 @@ func TestGitlabClient_PullIsMergeable(t *testing.T) { noHeadPipelineMR, false, }, + { + fmt.Sprintf("%s/plan", vcsStatusName), + models.SuccessCommitStatus, + gitlabServerVersions, + noHeadPipelineMR, + true, + }, } for _, serverVersion := range gitlabServerVersions { for _, c := range cases { diff --git a/server/events/vcs/instrumented_client.go b/server/events/vcs/instrumented_client.go index 4db0cb9ce3..2868548d6f 100644 --- a/server/events/vcs/instrumented_client.go +++ b/server/events/vcs/instrumented_client.go @@ -4,7 +4,7 @@ import ( "fmt" "strconv" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/logging" "github.com/runatlantis/atlantis/server/metrics" diff --git a/server/events/vcs/mocks/mock_github_pull_request_getter.go b/server/events/vcs/mocks/mock_github_pull_request_getter.go index 436d858363..a1082be8e7 100644 --- a/server/events/vcs/mocks/mock_github_pull_request_getter.go +++ b/server/events/vcs/mocks/mock_github_pull_request_getter.go @@ -4,7 +4,7 @@ package mocks import ( - github "github.com/google/go-github/v53/github" + github "github.com/google/go-github/v54/github" pegomock "github.com/petergtz/pegomock/v4" models "github.com/runatlantis/atlantis/server/events/models" "reflect" diff --git a/server/events/vcs/testdata/fixtures.go b/server/events/vcs/testdata/fixtures.go index ac66d58a99..00bde758d0 100644 --- a/server/events/vcs/testdata/fixtures.go +++ b/server/events/vcs/testdata/fixtures.go @@ -22,7 +22,7 @@ import ( "testing" "github.com/golang-jwt/jwt/v5" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" "github.com/mcdafydd/go-azuredevops/azuredevops" ) diff --git a/server/events/vcs/testdata/github-branch-protection-no-required-checks.json b/server/events/vcs/testdata/github-branch-protection-no-required-checks.json new file mode 100644 index 0000000000..4dd1496b79 --- /dev/null +++ b/server/events/vcs/testdata/github-branch-protection-no-required-checks.json @@ -0,0 +1,10 @@ +{ + "url": "https://api.github.com/repos/octocat/repo/branches/master/protection", + "required_pull_request_reviews": { + "url": "https://api.github.com/repos/octocat/repo/branches/master/protection/required_pull_request_reviews", + "dismiss_stale_reviews": false, + "require_code_owner_reviews": false, + "require_last_push_approval": false, + "required_approving_review_count": 1 + } +} diff --git a/server/events/vcs/testdata/github-commit-check-suites-check-runs-completed.json b/server/events/vcs/testdata/github-commit-check-suites-check-runs-completed.json new file mode 100644 index 0000000000..125e4d1ddf --- /dev/null +++ b/server/events/vcs/testdata/github-commit-check-suites-check-runs-completed.json @@ -0,0 +1,95 @@ +{ + "total_count": 1, + "check_runs": [ + { + "id": 4, + "head_sha": "ce587453ced02b1526dfb4cb910479d431683101", + "node_id": "MDg6Q2hlY2tSdW40", + "external_id": "", + "url": "https://api.github.com/repos/github/hello-world/check-runs/4", + "html_url": "https://github.com/github/hello-world/runs/4", + "details_url": "https://example.com", + "status": "completed", + "conclusion": "success", + "started_at": "2018-05-04T01:14:52Z", + "completed_at": "2018-05-04T01:14:52Z", + "output": { + "title": "Mighty Readme report", + "summary": "There are 0 failures, 2 warnings, and 1 notice.", + "text": "You may have some misspelled words on lines 2 and 4. You also may want to add a section in your README about how to install your app.", + "annotations_count": 2, + "annotations_url": "https://api.github.com/repos/github/hello-world/check-runs/4/annotations" + }, + "name": "mighty_readme", + "check_suite": { + "id": 5 + }, + "app": { + "id": 1, + "slug": "octoapp", + "node_id": "MDExOkludGVncmF0aW9uMQ==", + "owner": { + "login": "github", + "id": 1, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE=", + "url": "https://api.github.com/orgs/github", + "repos_url": "https://api.github.com/orgs/github/repos", + "events_url": "https://api.github.com/orgs/github/events", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": true + }, + "name": "Octocat App", + "description": "", + "external_url": "https://example.com", + "html_url": "https://github.com/apps/octoapp", + "created_at": "2017-07-08T16:18:44-04:00", + "updated_at": "2017-07-08T16:18:44-04:00", + "permissions": { + "metadata": "read", + "contents": "read", + "issues": "write", + "single_file": "write" + }, + "events": [ + "push", + "pull_request" + ] + }, + "pull_requests": [ + { + "url": "https://api.github.com/repos/github/hello-world/pulls/1", + "id": 1934, + "number": 3956, + "head": { + "ref": "say-hello", + "sha": "3dca65fa3e8d4b3da3f3d056c59aee1c50f41390", + "repo": { + "id": 526, + "url": "https://api.github.com/repos/github/hello-world", + "name": "hello-world" + } + }, + "base": { + "ref": "master", + "sha": "e7fdf7640066d71ad16a86fbcbb9c6a10a18af4f", + "repo": { + "id": 526, + "url": "https://api.github.com/repos/github/hello-world", + "name": "hello-world" + } + } + } + ] + } + ] +} diff --git a/server/events/vcs/testdata/github-commit-check-suites-completed.json b/server/events/vcs/testdata/github-commit-check-suites-completed.json new file mode 100644 index 0000000000..b8af9c32a9 --- /dev/null +++ b/server/events/vcs/testdata/github-commit-check-suites-completed.json @@ -0,0 +1,169 @@ +{ + "total_count": 1, + "check_suites": [ + { + "id": 1234567890, + "node_id": "CS_kwDOHE7PYM8AAAAB2iIZfQ", + "head_branch": "atlantis-patch-2", + "head_sha": "4273e07c528292222f119a040079093bf1f11232", + "status": "completed", + "conclusion": null, + "url": "https://api.github.com/repos/octocat/Hello-World/check-suites/1234567890", + "before": "0000000000000000000000000000000000000000", + "after": "4273e07c528292222f119a040079093bf1f11232", + "pull_requests": [ + { + "url": "https://api.github.com/repos/octocat/Hello-World/pulls/1", + "id": 1035065545, + "number": 1, + "head": { + "ref": "atlantis-patch-2", + "sha": "4273e07c528292222f119a040079093bf1f11232", + "repo": { + "id": 474926944, + "url": "https://api.github.com/repos/octocat/Hello-World", + "name": "Hello-World" + } + }, + "base": { + "ref": "main", + "sha": "6f5744874b33ceb6a5c91edc91085991dbd1f61a", + "repo": { + "id": 474926944, + "url": "https://api.github.com/repos/octocat/Hello-World", + "name": "Hello-World" + } + } + } + ], + "app": { + "id": 184783, + "slug": "atlantis", + "node_id": "A_kwHOBbMkBs4AAtHP", + "owner": { + "login": "octocat", + "id": 95626246, + "node_id": "O_kgDOBbMkBg", + "avatar_url": "https://avatars.githubusercontent.com/u/95626246?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "Organization", + "site_admin": false + }, + "name": "atlantis", + "description": "", + "external_url": "https://atlantis.localhost/", + "html_url": "https://github.com/apps/atlantis", + "created_at": "2022-03-29T08:51:26Z", + "updated_at": "2022-07-01T11:35:37Z", + "permissions": { + "administration": "read", + "checks": "write", + "contents": "write", + "issues": "write", + "metadata": "read", + "pull_requests": "write", + "statuses": "write" + }, + "events": [] + }, + "created_at": "2022-08-24T07:06:21Z", + "updated_at": "2022-08-24T07:06:21Z", + "rerequestable": true, + "runs_rerequestable": true, + "latest_check_runs_count": 0, + "check_runs_url": "https://api.github.com/repos/octocat/Hello-World/check-suites/1234567890/check-runs", + "head_commit": { + "id": "4273e07c528292222f119a040079093bf1f11232", + "tree_id": "56781332464aabdfae51b7f37f72ffc6ce8ce54e", + "message": "test atlantis", + "timestamp": "2022-08-24T07:06:21Z", + "author": { + "name": "octocat", + "email": "octocat@noreply.github.com" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com" + } + }, + "repository": { + "id": 474926944, + "node_id": "R_kgDOHE7PYA", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "private": true, + "owner": { + "login": "octocat", + "id": 95626246, + "node_id": "O_kgDOBbMkBg", + "avatar_url": "https://avatars.githubusercontent.com/u/95626246?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/octocat/Hello-World", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "forks_url": "https://api.github.com/repos/octocat/Hello-World/forks", + "keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/octocat/Hello-World/teams", + "hooks_url": "https://api.github.com/repos/octocat/Hello-World/hooks", + "issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "events_url": "https://api.github.com/repos/octocat/Hello-World/events", + "assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "tags_url": "https://api.github.com/repos/octocat/Hello-World/tags", + "blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "languages_url": "https://api.github.com/repos/octocat/Hello-World/languages", + "stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers", + "contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors", + "subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription", + "commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/octocat/Hello-World/merges", + "archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads", + "issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}", + "pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}", + "releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}", + "deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments" + } + } + ] +} diff --git a/server/events/webhooks/slack.go b/server/events/webhooks/slack.go index 54116de486..091297c74c 100644 --- a/server/events/webhooks/slack.go +++ b/server/events/webhooks/slack.go @@ -25,24 +25,26 @@ import ( type SlackWebhook struct { Client SlackClient WorkspaceRegex *regexp.Regexp + BranchRegex *regexp.Regexp Channel string } -func NewSlack(r *regexp.Regexp, channel string, client SlackClient) (*SlackWebhook, error) { +func NewSlack(wr *regexp.Regexp, br *regexp.Regexp, channel string, client SlackClient) (*SlackWebhook, error) { if err := client.AuthTest(); err != nil { return nil, fmt.Errorf("testing slack authentication: %s. Verify your slack-token is valid", err) } return &SlackWebhook{ Client: client, - WorkspaceRegex: r, + WorkspaceRegex: wr, + BranchRegex: br, Channel: channel, }, nil } -// Send sends the webhook to Slack if the workspace matches the regex. +// Send sends the webhook to Slack if workspace and branch matches their respective regex. func (s *SlackWebhook) Send(log logging.SimpleLogging, applyResult ApplyResult) error { - if !s.WorkspaceRegex.MatchString(applyResult.Workspace) { + if !s.WorkspaceRegex.MatchString(applyResult.Workspace) || !s.BranchRegex.MatchString(applyResult.Pull.BaseBranch) { return nil } return s.Client.PostMessage(s.Channel, applyResult) diff --git a/server/events/webhooks/slack_client.go b/server/events/webhooks/slack_client.go index 3a744b9241..a548f9ea31 100644 --- a/server/events/webhooks/slack_client.go +++ b/server/events/webhooks/slack_client.go @@ -102,6 +102,11 @@ func (d *DefaultSlackClient) createAttachments(applyResult ApplyResult) []slack. Value: applyResult.Workspace, Short: true, }, + { + Title: "Branch", + Value: applyResult.Pull.BaseBranch, + Short: true, + }, { Title: "User", Value: applyResult.User.Username, diff --git a/server/events/webhooks/slack_client_test.go b/server/events/webhooks/slack_client_test.go index 83db303247..3edd5ba0ef 100644 --- a/server/events/webhooks/slack_client_test.go +++ b/server/events/webhooks/slack_client_test.go @@ -163,8 +163,9 @@ func setup(t *testing.T) { FullName: "runatlantis/atlantis", }, Pull: models.PullRequest{ - Num: 1, - URL: "url", + Num: 1, + URL: "url", + BaseBranch: "main", }, User: models.User{ Username: "lkysow", diff --git a/server/events/webhooks/slack_test.go b/server/events/webhooks/slack_test.go index dd80d93e4d..0a88a2f310 100644 --- a/server/events/webhooks/slack_test.go +++ b/server/events/webhooks/slack_test.go @@ -18,6 +18,7 @@ import ( "testing" . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/webhooks" "github.com/runatlantis/atlantis/server/events/webhooks/mocks" "github.com/runatlantis/atlantis/server/logging" @@ -35,10 +36,14 @@ func TestSend_PostMessage(t *testing.T) { hook := webhooks.SlackWebhook{ Client: client, WorkspaceRegex: regex, + BranchRegex: regex, Channel: channel, } result := webhooks.ApplyResult{ Workspace: "production", + Pull: models.PullRequest{ + BaseBranch: "main", + }, } t.Log("PostMessage should be called, doesn't matter if it errors or not") @@ -57,10 +62,14 @@ func TestSend_NoopSuccess(t *testing.T) { hook := webhooks.SlackWebhook{ Client: client, WorkspaceRegex: regex, + BranchRegex: regex, Channel: channel, } result := webhooks.ApplyResult{ Workspace: "production", + Pull: models.PullRequest{ + BaseBranch: "main", + }, } err = hook.Send(logging.NewNoopLogger(t), result) Ok(t, err) diff --git a/server/events/webhooks/webhooks.go b/server/events/webhooks/webhooks.go index 080400f9ab..c4b43239a7 100644 --- a/server/events/webhooks/webhooks.go +++ b/server/events/webhooks/webhooks.go @@ -52,6 +52,7 @@ type MultiWebhookSender struct { type Config struct { Event string WorkspaceRegex string + BranchRegex string Kind string Channel string } @@ -59,7 +60,11 @@ type Config struct { func NewMultiWebhookSender(configs []Config, client SlackClient) (*MultiWebhookSender, error) { var webhooks []Sender for _, c := range configs { - r, err := regexp.Compile(c.WorkspaceRegex) + wr, err := regexp.Compile(c.WorkspaceRegex) + if err != nil { + return nil, err + } + br, err := regexp.Compile(c.BranchRegex) if err != nil { return nil, err } @@ -77,7 +82,7 @@ func NewMultiWebhookSender(configs []Config, client SlackClient) (*MultiWebhookS if c.Channel == "" { return nil, errors.New("must specify \"channel\" if using a webhook of \"kind: slack\"") } - slack, err := NewSlack(r, c.Channel, client) + slack, err := NewSlack(wr, br, c.Channel, client) if err != nil { return nil, err } diff --git a/server/events/webhooks/webhooks_test.go b/server/events/webhooks/webhooks_test.go index 03437f528c..5ee00bf599 100644 --- a/server/events/webhooks/webhooks_test.go +++ b/server/events/webhooks/webhooks_test.go @@ -34,6 +34,7 @@ const ( var validConfig = webhooks.Config{ Event: validEvent, WorkspaceRegex: validRegex, + BranchRegex: validRegex, Kind: validKind, Channel: validChannel, } @@ -42,8 +43,8 @@ func validConfigs() []webhooks.Config { return []webhooks.Config{validConfig} } -func TestNewWebhooksManager_InvalidRegex(t *testing.T) { - t.Log("When given an invalid regex in a config, an error is returned") +func TestNewWebhooksManager_InvalidWorkspaceRegex(t *testing.T) { + t.Log("When given an invalid workspace regex in a config, an error is returned") RegisterMockTestingT(t) client := mocks.NewMockSlackClient() @@ -55,6 +56,33 @@ func TestNewWebhooksManager_InvalidRegex(t *testing.T) { Assert(t, strings.Contains(err.Error(), "error parsing regexp"), "expected regex error") } +func TestNewWebhooksManager_InvalidBranchRegex(t *testing.T) { + t.Log("When given an invalid branch regex in a config, an error is returned") + RegisterMockTestingT(t) + client := mocks.NewMockSlackClient() + + invalidRegex := "(" + configs := validConfigs() + configs[0].BranchRegex = invalidRegex + _, err := webhooks.NewMultiWebhookSender(configs, client) + Assert(t, err != nil, "expected error") + Assert(t, strings.Contains(err.Error(), "error parsing regexp"), "expected regex error") +} + +func TestNewWebhooksManager_InvalidBranchAndWorkspaceRegex(t *testing.T) { + t.Log("When given an invalid branch and invalid workspace regex in a config, an error is returned") + RegisterMockTestingT(t) + client := mocks.NewMockSlackClient() + + invalidRegex := "(" + configs := validConfigs() + configs[0].WorkspaceRegex = invalidRegex + configs[0].BranchRegex = invalidRegex + _, err := webhooks.NewMultiWebhookSender(configs, client) + Assert(t, err != nil, "expected error") + Assert(t, strings.Contains(err.Error(), "error parsing regexp"), "expected regex error") +} + func TestNewWebhooksManager_NoEvent(t *testing.T) { t.Log("When the event key is not specified in a config, an error is returned") RegisterMockTestingT(t) diff --git a/server/events/working_dir.go b/server/events/working_dir.go index db016dce17..65fd28a304 100644 --- a/server/events/working_dir.go +++ b/server/events/working_dir.go @@ -32,8 +32,8 @@ const workingDirPrefix = "repos" var cloneLocks sync.Map -//go:generate pegomock generate --package mocks -o mocks/mock_working_dir.go WorkingDir -//go:generate pegomock generate --package events WorkingDir +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_working_dir.go WorkingDir +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package events WorkingDir // WorkingDir handles the workspace on disk for running commands. type WorkingDir interface { @@ -56,6 +56,8 @@ type WorkingDir interface { SetSafeToReClone() // DeletePlan deletes the plan for this repo, pull, workspace path and project name DeletePlan(r models.Repo, p models.PullRequest, workspace string, path string, projectName string) error + // GetGitUntrackedFiles returns a list of Git untracked files in the working dir. + GetGitUntrackedFiles(r models.Repo, p models.PullRequest, workspace string) ([]string, error) } // FileWorkspace implements WorkingDir with the file system. @@ -382,3 +384,24 @@ func (w *FileWorkspace) DeletePlan(r models.Repo, p models.PullRequest, workspac w.Logger.Info("Deleting plan: " + planPath) return os.Remove(planPath) } + +// getGitUntrackedFiles returns a list of Git untracked files in the working dir. +func (w *FileWorkspace) GetGitUntrackedFiles(r models.Repo, p models.PullRequest, workspace string) ([]string, error) { + workingDir, err := w.GetWorkingDir(r, p, workspace) + if err != nil { + return nil, err + } + + w.Logger.Debug("Checking for Git untracked files in directory: '%s'", workingDir) + cmd := exec.Command("git", "ls-files", "--others", "--exclude-standard") + cmd.Dir = workingDir + + output, err := cmd.CombinedOutput() + if err != nil { + return nil, err + } + + untrackedFiles := strings.Split(string(output), "\n")[:] + w.Logger.Debug("Untracked files: '%s'", strings.Join(untrackedFiles, ",")) + return untrackedFiles, nil +} diff --git a/server/server.go b/server/server.go index 19d6cd69d1..9bab76bf78 100644 --- a/server/server.go +++ b/server/server.go @@ -141,6 +141,10 @@ type WebhookConfig struct { // that is being modified for this event. If the regex matches, we'll // send the webhook, ex. "production.*". WorkspaceRegex string `mapstructure:"workspace-regex"` + // BranchRegex is a regex that is used to match against the base branch + // that is being modified for this event. If the regex matches, we'll + // send the webhook, ex. "main.*". + BranchRegex string `mapstructure:"branch-regex"` // Kind is the type of webhook we should send, ex. slack. Kind string `mapstructure:"kind"` // Channel is the channel to send this webhook to. It only applies to @@ -344,6 +348,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { for _, c := range userConfig.Webhooks { config := webhooks.Config{ Channel: c.Channel, + BranchRegex: c.BranchRegex, Event: c.Event, Kind: c.Kind, WorkspaceRegex: c.WorkspaceRegex, @@ -591,6 +596,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { userConfig.AutoplanFileList, userConfig.RestrictFileList, userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, statsScope, logger, terraformClient, @@ -791,6 +797,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { AzureDevopsPullGetter: azuredevopsClient, CommentCommandRunnerByCmd: commentCommandRunnerByCmd, EventParser: eventParser, + FailOnPreWorkflowHookError: userConfig.FailOnPreWorkflowHookError, Logger: logger, GlobalCfg: globalCfg, StatsScope: statsScope.SubScope("cmd"), diff --git a/server/user_config.go b/server/user_config.go index 209482049e..7104b2df5a 100644 --- a/server/user_config.go +++ b/server/user_config.go @@ -11,37 +11,39 @@ import ( // The mapstructure tags correspond to flags in cmd/server.go and are used when // the config is parsed from a YAML file. type UserConfig struct { - AllowForkPRs bool `mapstructure:"allow-fork-prs"` - AllowRepoConfig bool `mapstructure:"allow-repo-config"` - AllowCommands string `mapstructure:"allow-commands"` - AtlantisURL string `mapstructure:"atlantis-url"` - Automerge bool `mapstructure:"automerge"` - AutoplanFileList string `mapstructure:"autoplan-file-list"` - AutoplanModules bool `mapstructure:"autoplan-modules"` - AutoplanModulesFromProjects string `mapstructure:"autoplan-modules-from-projects"` - AzureDevopsToken string `mapstructure:"azuredevops-token"` - AzureDevopsUser string `mapstructure:"azuredevops-user"` - AzureDevopsWebhookPassword string `mapstructure:"azuredevops-webhook-password"` - AzureDevopsWebhookUser string `mapstructure:"azuredevops-webhook-user"` - AzureDevOpsHostname string `mapstructure:"azuredevops-hostname"` - BitbucketBaseURL string `mapstructure:"bitbucket-base-url"` - BitbucketToken string `mapstructure:"bitbucket-token"` - BitbucketUser string `mapstructure:"bitbucket-user"` - BitbucketWebhookSecret string `mapstructure:"bitbucket-webhook-secret"` - CheckoutDepth int `mapstructure:"checkout-depth"` - CheckoutStrategy string `mapstructure:"checkout-strategy"` - DataDir string `mapstructure:"data-dir"` - DisableApplyAll bool `mapstructure:"disable-apply-all"` - DisableApply bool `mapstructure:"disable-apply"` - DisableAutoplan bool `mapstructure:"disable-autoplan"` - DisableMarkdownFolding bool `mapstructure:"disable-markdown-folding"` - DisableRepoLocking bool `mapstructure:"disable-repo-locking"` - DiscardApprovalOnPlanFlag bool `mapstructure:"discard-approval-on-plan"` - EmojiReaction string `mapstructure:"emoji-reaction"` - EnablePolicyChecksFlag bool `mapstructure:"enable-policy-checks"` - EnableRegExpCmd bool `mapstructure:"enable-regexp-cmd"` - EnableDiffMarkdownFormat bool `mapstructure:"enable-diff-markdown-format"` - ExecutableName string `mapstructure:"executable-name"` + AllowForkPRs bool `mapstructure:"allow-fork-prs"` + AllowRepoConfig bool `mapstructure:"allow-repo-config"` + AllowCommands string `mapstructure:"allow-commands"` + AtlantisURL string `mapstructure:"atlantis-url"` + Automerge bool `mapstructure:"automerge"` + AutoplanFileList string `mapstructure:"autoplan-file-list"` + AutoplanModules bool `mapstructure:"autoplan-modules"` + AutoplanModulesFromProjects string `mapstructure:"autoplan-modules-from-projects"` + AzureDevopsToken string `mapstructure:"azuredevops-token"` + AzureDevopsUser string `mapstructure:"azuredevops-user"` + AzureDevopsWebhookPassword string `mapstructure:"azuredevops-webhook-password"` + AzureDevopsWebhookUser string `mapstructure:"azuredevops-webhook-user"` + AzureDevOpsHostname string `mapstructure:"azuredevops-hostname"` + BitbucketBaseURL string `mapstructure:"bitbucket-base-url"` + BitbucketToken string `mapstructure:"bitbucket-token"` + BitbucketUser string `mapstructure:"bitbucket-user"` + BitbucketWebhookSecret string `mapstructure:"bitbucket-webhook-secret"` + CheckoutDepth int `mapstructure:"checkout-depth"` + CheckoutStrategy string `mapstructure:"checkout-strategy"` + DataDir string `mapstructure:"data-dir"` + DisableApplyAll bool `mapstructure:"disable-apply-all"` + DisableApply bool `mapstructure:"disable-apply"` + DisableAutoplan bool `mapstructure:"disable-autoplan"` + DisableMarkdownFolding bool `mapstructure:"disable-markdown-folding"` + DisableRepoLocking bool `mapstructure:"disable-repo-locking"` + DiscardApprovalOnPlanFlag bool `mapstructure:"discard-approval-on-plan"` + EmojiReaction string `mapstructure:"emoji-reaction"` + EnablePolicyChecksFlag bool `mapstructure:"enable-policy-checks"` + EnableRegExpCmd bool `mapstructure:"enable-regexp-cmd"` + EnableDiffMarkdownFormat bool `mapstructure:"enable-diff-markdown-format"` + ExecutableName string `mapstructure:"executable-name"` + // Fail and do not run the Atlantis command request if any of the pre workflow hooks error. + FailOnPreWorkflowHookError bool `mapstructure:"fail-on-pre-workflow-hook-error"` HideUnchangedPlanComments bool `mapstructure:"hide-unchanged-plan-comments"` GithubAllowMergeableBypassApply bool `mapstructure:"gh-allow-mergeable-bypass-apply"` GithubHostname string `mapstructure:"gh-hostname"` @@ -58,6 +60,7 @@ type UserConfig struct { GitlabToken string `mapstructure:"gitlab-token"` GitlabUser string `mapstructure:"gitlab-user"` GitlabWebhookSecret string `mapstructure:"gitlab-webhook-secret"` + IncludeGitUntrackedFiles bool `mapstructure:"include-git-untracked-files"` APISecret string `mapstructure:"api-secret"` HidePrevPlanComments bool `mapstructure:"hide-prev-plan-comments"` LockingDBType string `mapstructure:"locking-db-type"` diff --git a/testdrive/github.go b/testdrive/github.go index b0c93c1e77..5e02a2bf50 100644 --- a/testdrive/github.go +++ b/testdrive/github.go @@ -18,7 +18,7 @@ import ( "strings" "time" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" ) var githubUsername string diff --git a/testdrive/testdrive.go b/testdrive/testdrive.go index aa5774b5cb..b852437d8e 100644 --- a/testdrive/testdrive.go +++ b/testdrive/testdrive.go @@ -31,7 +31,7 @@ import ( "time" "github.com/briandowns/spinner" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v54/github" "github.com/mitchellh/colorstring" "github.com/pkg/errors" ) diff --git a/testdrive/utils.go b/testdrive/utils.go index aa2371e855..15ce864c94 100644 --- a/testdrive/utils.go +++ b/testdrive/utils.go @@ -35,7 +35,7 @@ import ( ) const hashicorpReleasesURL = "https://releases.hashicorp.com" -const terraformVersion = "1.5.5" // renovate: datasource=github-releases depName=hashicorp/terraform versioning=hashicorp +const terraformVersion = "1.5.7" // renovate: datasource=github-releases depName=hashicorp/terraform versioning=hashicorp const ngrokDownloadURL = "https://bin.equinox.io/c/4VmDzA7iaHb" const ngrokAPIURL = "localhost:41414" // We hope this isn't used. const atlantisPort = 4141 diff --git a/testing/Dockerfile b/testing/Dockerfile index 564d83952c..22527bf5f8 100644 --- a/testing/Dockerfile +++ b/testing/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.21.0 +FROM golang:1.21.1 RUN apt-get update && apt-get --no-install-recommends -y install unzip \ && apt-get clean \ @@ -6,7 +6,7 @@ RUN apt-get update && apt-get --no-install-recommends -y install unzip \ # Install Terraform # renovate: datasource=github-releases depName=hashicorp/terraform versioning=hashicorp -ENV TERRAFORM_VERSION=1.5.5 +ENV TERRAFORM_VERSION=1.5.7 RUN case $(uname -m) in x86_64|amd64) ARCH="amd64" ;; aarch64|arm64|armv7l) ARCH="arm64" ;; esac && \ wget -nv -O terraform.zip https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_${ARCH}.zip && \ mkdir -p /usr/local/bin/tf/versions/${TERRAFORM_VERSION} && \ @@ -16,7 +16,7 @@ RUN case $(uname -m) in x86_64|amd64) ARCH="amd64" ;; aarch64|arm64|armv7l) ARCH # Install conftest # renovate: datasource=github-releases depName=open-policy-agent/conftest -ENV CONFTEST_VERSION=0.44.1 +ENV CONFTEST_VERSION=0.45.0 SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN case $(uname -m) in x86_64|amd64) ARCH="x86_64" ;; aarch64|arm64|armv7l) ARCH="arm64" ;; esac && \ curl -LOs https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/conftest_${CONFTEST_VERSION}_Linux_${ARCH}.tar.gz && \ diff --git a/yarn.lock b/yarn.lock index f761bb2635..d679ac3889 100644 --- a/yarn.lock +++ b/yarn.lock @@ -134,32 +134,32 @@ "@algolia/requester-common" "4.19.1" "@babel/parser@^7.20.15", "@babel/parser@^7.21.3": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.10.tgz#e37634f9a12a1716136c44624ef54283cabd3f55" - integrity sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ== + version "7.22.16" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95" + integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA== -"@docsearch/css@3.5.1", "@docsearch/css@^3.5.1": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.5.1.tgz#4adf9884735bbfea621c3716e80ea97baa419b73" - integrity sha512-2Pu9HDg/uP/IT10rbQ+4OrTQuxIWdKVUEdcw9/w7kZJv9NeHS6skJx1xuRiFyoGKwAzcHXnLp7csE99sj+O1YA== +"@docsearch/css@3.5.2", "@docsearch/css@^3.5.1": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.5.2.tgz#610f47b48814ca94041df969d9fcc47b91fc5aac" + integrity sha512-SPiDHaWKQZpwR2siD0KQUwlStvIAnEyK6tAE2h2Wuoq8ue9skzhlyVQ1ddzOxX6khULnAALDiR/isSF3bnuciA== "@docsearch/js@^3.5.1": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@docsearch/js/-/js-3.5.1.tgz#6d8de3b4fcf7de94462c0e592e333efa9ebbbabd" - integrity sha512-EXi8de5njxgP6TV3N9ytnGRLG9zmBNTEZjR4VzwPcpPLbZxxTLG2gaFyJyKiFVQxHW/DPlMrDJA3qoRRGEkgZw== + version "3.5.2" + resolved "https://registry.yarnpkg.com/@docsearch/js/-/js-3.5.2.tgz#a11cb2e7e62890e9e940283fed6972ecf632629d" + integrity sha512-p1YFTCDflk8ieHgFJYfmyHBki1D61+U9idwrLh+GQQMrBSP3DLGKpy0XUJtPjAOPltcVbqsTjiPFfH7JImjUNg== dependencies: - "@docsearch/react" "3.5.1" + "@docsearch/react" "3.5.2" preact "^10.0.0" -"@docsearch/react@3.5.1", "@docsearch/react@^3.5.1": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-3.5.1.tgz#35f4a75f948211d8bb6830d2147c575f96a85274" - integrity sha512-t5mEODdLzZq4PTFAm/dvqcvZFdPDMdfPE5rJS5SC8OUq9mPzxEy6b+9THIqNM9P0ocCb4UC5jqBrxKclnuIbzQ== +"@docsearch/react@3.5.2", "@docsearch/react@^3.5.1": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-3.5.2.tgz#2e6bbee00eb67333b64906352734da6aef1232b9" + integrity sha512-9Ahcrs5z2jq/DcAvYtvlqEBHImbm4YJI8M9y0x6Tqg598P40HTEkX7hsMcIuThI+hTFxRGZ9hll0Wygm2yEjng== dependencies: "@algolia/autocomplete-core" "1.9.3" "@algolia/autocomplete-preset-algolia" "1.9.3" - "@docsearch/css" "3.5.1" - algoliasearch "^4.0.0" + "@docsearch/css" "3.5.2" + algoliasearch "^4.19.1" "@esbuild/android-arm64@0.18.20": version "0.18.20" @@ -276,70 +276,70 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== -"@mdit-vue/plugin-component@^0.12.0": - version "0.12.0" - resolved "https://registry.yarnpkg.com/@mdit-vue/plugin-component/-/plugin-component-0.12.0.tgz#7a52837935e2cbc9b6cf22fd5f9349f6199fc18c" - integrity sha512-LrwV3f0Y6H7b7m/w1Y3bkGuR3HOiBK4QiHHW3HuRMza6MZodDQbj8Baik5/V5GiSg1/ltijS1CymVcycd1EfTw== +"@mdit-vue/plugin-component@^0.12.0", "@mdit-vue/plugin-component@^0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@mdit-vue/plugin-component/-/plugin-component-0.12.1.tgz#ed04c94c767e4ba1f6fc16ab458da82750b401f6" + integrity sha512-L3elbvuKUufXwPLHrmJGd/ijd/QKxfcHXy3kRy4O+P7UIV7HSWePpfB0k+wWee+by3MviYYxjVAi392z+DGy3Q== dependencies: - "@types/markdown-it" "^12.2.3" + "@types/markdown-it" "^13.0.0" markdown-it "^13.0.1" -"@mdit-vue/plugin-frontmatter@^0.12.0": - version "0.12.0" - resolved "https://registry.yarnpkg.com/@mdit-vue/plugin-frontmatter/-/plugin-frontmatter-0.12.0.tgz#fb344646241bed1bae5f8bd320c7b2f493bd8b67" - integrity sha512-26Y3JktjGgNoCVH7NLqi5RcdAauAqxepTt2qXueRcRHtGpiRQV2/M1FveIhCOTCtHSuG5bBOHUxGaV6vRK3Vbw== +"@mdit-vue/plugin-frontmatter@^0.12.0", "@mdit-vue/plugin-frontmatter@^0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@mdit-vue/plugin-frontmatter/-/plugin-frontmatter-0.12.1.tgz#af02ebc6622fa24d71343fde627a0e49d4ffbab5" + integrity sha512-C6ycNjrJ+T4JgbVxwo9cUkfLacOO841Yl8ogqd5PJmAVpc5cM2OLBkqqkZxNRXos3g9xM1VvIQ7gK/047UNADg== dependencies: "@mdit-vue/types" "0.12.0" - "@types/markdown-it" "^12.2.3" + "@types/markdown-it" "^13.0.0" gray-matter "^4.0.3" markdown-it "^13.0.1" -"@mdit-vue/plugin-headers@^0.12.0": - version "0.12.0" - resolved "https://registry.yarnpkg.com/@mdit-vue/plugin-headers/-/plugin-headers-0.12.0.tgz#c16921e071b2766fd04a703d8d42ead00561f44c" - integrity sha512-7qR63J2uc/rXbjHT77WoYBm9imwzx1tVESmRK+Uth6kqFvSWAXAFPcm4PBatGEE8TgzhklPs5BTcQtQhmmsyaw== +"@mdit-vue/plugin-headers@^0.12.0", "@mdit-vue/plugin-headers@^0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@mdit-vue/plugin-headers/-/plugin-headers-0.12.1.tgz#2ab8c446fca6d39ce951819b5e18fef614a227aa" + integrity sha512-DXAw/iWW8f3qUYMDHgQmamL+XGjnaoeRzdvDseLRyr7gXX4xpYO9OIhe/pv9LzSvUoY7UGYmn4kFeI+0qpWJ+g== dependencies: - "@mdit-vue/shared" "0.12.0" + "@mdit-vue/shared" "0.12.1" "@mdit-vue/types" "0.12.0" - "@types/markdown-it" "^12.2.3" + "@types/markdown-it" "^13.0.0" markdown-it "^13.0.1" -"@mdit-vue/plugin-sfc@^0.12.0": - version "0.12.0" - resolved "https://registry.yarnpkg.com/@mdit-vue/plugin-sfc/-/plugin-sfc-0.12.0.tgz#2932c333657ddaf6d76664118b83c93d5dd4f727" - integrity sha512-mH+rHsERzDxGucAQJILspRiD723AIWMmtMhp7lDKdkCIbIhYfupFv/CkSeX+LAx5UY5greWvUTPGYVKn4gw/5Q== +"@mdit-vue/plugin-sfc@^0.12.0", "@mdit-vue/plugin-sfc@^0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@mdit-vue/plugin-sfc/-/plugin-sfc-0.12.1.tgz#49d6060e71e4016252ac35140f6960eb9a50cb6f" + integrity sha512-6j332CsSqumy1+StIM3XphdXG1zj9NXuWestDJrKgS3OLy5P0EAioXScUYiZYysw61ZG+2pP37MW7Hg+eHbyIg== dependencies: "@mdit-vue/types" "0.12.0" - "@types/markdown-it" "^12.2.3" + "@types/markdown-it" "^13.0.0" markdown-it "^13.0.1" -"@mdit-vue/plugin-title@^0.12.0": - version "0.12.0" - resolved "https://registry.yarnpkg.com/@mdit-vue/plugin-title/-/plugin-title-0.12.0.tgz#e69f33036972a7a67c3321647bdbcb1b9a5b6f4e" - integrity sha512-XrQcior1EmPgsDG88KsoF4LUSQw/RS1Nyfn5xNWGiurO70a2hml4kCe0XzT4sLKUAPG0HNbIY6b92ezNezqWTg== +"@mdit-vue/plugin-title@^0.12.0", "@mdit-vue/plugin-title@^0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@mdit-vue/plugin-title/-/plugin-title-0.12.1.tgz#d01c2b0e9fd374fc3d52a551689cadf5fe066890" + integrity sha512-JOsiDj+CryGbrTDWUnDAwB9kSkN6o9GDo3udR6BPDgBNVb3zAnx9ZNaRpEhDW1LnQhf9/LYicWJ2eTNRKPcJNQ== dependencies: - "@mdit-vue/shared" "0.12.0" + "@mdit-vue/shared" "0.12.1" "@mdit-vue/types" "0.12.0" - "@types/markdown-it" "^12.2.3" + "@types/markdown-it" "^13.0.0" markdown-it "^13.0.1" -"@mdit-vue/plugin-toc@^0.12.0": - version "0.12.0" - resolved "https://registry.yarnpkg.com/@mdit-vue/plugin-toc/-/plugin-toc-0.12.0.tgz#bf8c4c4d13dc9ef8dc3c4b8213e3846312cca7f3" - integrity sha512-tT985CqvLp17DFWHrSvmmJbh7qcy0Rl0dBbYN//Fn952a04dbr1mb2LqW0B1oStSAQj2q24HpK4ZPgYOt7Z1Jg== +"@mdit-vue/plugin-toc@^0.12.0", "@mdit-vue/plugin-toc@^0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@mdit-vue/plugin-toc/-/plugin-toc-0.12.1.tgz#ed650a05d3f4b84637e79d8b3b06e89295cc78bf" + integrity sha512-nFGwTwVa8GLCKJMV7cGST7lYuljSjEiCTPgKIpQ/WifwouHsQaL/rnBDr22kpzY2hRTAhM3+TT5GDwLyxa/e6A== dependencies: - "@mdit-vue/shared" "0.12.0" + "@mdit-vue/shared" "0.12.1" "@mdit-vue/types" "0.12.0" - "@types/markdown-it" "^12.2.3" + "@types/markdown-it" "^13.0.0" markdown-it "^13.0.1" -"@mdit-vue/shared@0.12.0", "@mdit-vue/shared@^0.12.0": - version "0.12.0" - resolved "https://registry.yarnpkg.com/@mdit-vue/shared/-/shared-0.12.0.tgz#e4e7d5ffb362dedb92b161fcbf05e81a3d2ac143" - integrity sha512-E+sGSubhvnp+Gmb2hJXFDxdLwwQD1H52EVbA4yrxxI5q/cwtnPIN2eJU3zlZB9KcvzXYDFFwt/x2mfhK8RZKBg== +"@mdit-vue/shared@0.12.1", "@mdit-vue/shared@^0.12.0", "@mdit-vue/shared@^0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@mdit-vue/shared/-/shared-0.12.1.tgz#b67cbfc71cac6fb49a7a0be169cd53d921e30344" + integrity sha512-bXgd0KThe4jC2leCFDFsyrudXIckvTwV4WnQK/rRMrXq0/BAuVdSNdIv1LGCWZxD5+oDyPyEPd0lalTIFwqsmg== dependencies: "@mdit-vue/types" "0.12.0" - "@types/markdown-it" "^12.2.3" + "@types/markdown-it" "^13.0.0" markdown-it "^13.0.1" "@mdit-vue/types@0.12.0", "@mdit-vue/types@^0.12.0": @@ -396,9 +396,9 @@ "@types/node" "*" "@types/linkify-it@*": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.2.tgz#fd2cd2edbaa7eaac7e7f3c1748b52a19143846c9" - integrity sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA== + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.3.tgz#15a0712296c5041733c79efe233ba17ae5a7587b" + integrity sha512-pTjcqY9E4nOI55Wgpz7eiI8+LzdYnw3qxXCfHyBDdPbYvbyLgWLJGh8EdPvqawwMK1Uo1794AUkkR38Fr0g+2g== "@types/markdown-it-emoji@^2.0.2": version "2.0.2" @@ -407,10 +407,10 @@ dependencies: "@types/markdown-it" "*" -"@types/markdown-it@*": - version "13.0.0" - resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-13.0.0.tgz#05e82614aa6d305a4d8efe24056d8879a9042970" - integrity sha512-mPTaUl5glYfzdJFeCsvhXQwZKdyszNAZcMm5ZTP5SfpTu+vIbog7J3z8Fa4x/Fzv5TB4R6OA/pHBYIYmkYOWGQ== +"@types/markdown-it@*", "@types/markdown-it@^13.0.0", "@types/markdown-it@^13.0.1": + version "13.0.1" + resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-13.0.1.tgz#2f45bd54315f5db2d9bd909ec7fd4d994cf75df4" + integrity sha512-SUEb8Frsxs3D5Gg9xek6i6EG6XQ5s+O+ZdQzIPESZVZw3Pv3CPQfjCJBI+RgqZd1IBeu18S0Rn600qpPnEK37w== dependencies: "@types/linkify-it" "*" "@types/mdurl" "*" @@ -434,9 +434,9 @@ integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== "@types/node@*": - version "20.5.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.0.tgz#7fc8636d5f1aaa3b21e6245e97d56b7f56702313" - integrity sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q== + version "20.6.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.0.tgz#9d7daa855d33d4efec8aea88cd66db1c2f0ebe16" + integrity sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg== "@types/web-bluetooth@^0.0.17": version "0.0.17" @@ -444,9 +444,9 @@ integrity sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA== "@vitejs/plugin-vue@^4.2.3": - version "4.2.3" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-4.2.3.tgz#ee0b6dfcc62fe65364e6395bf38fa2ba10bb44b6" - integrity sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw== + version "4.3.4" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-4.3.4.tgz#a289dff38e01949fe7be581d5542cabaeb961dec" + integrity sha512-ciXNIHKPriERBisHFBvnTbfKa6r9SAesOYXeGDzgegcvy9Q4xdScSHAmKbNT0M3O0S9LKhIf5/G+UYG4NnnzYw== "@vue/compiler-core@3.3.4": version "3.3.4" @@ -586,6 +586,17 @@ vue "^3.3.4" vue-router "^4.2.4" +"@vuepress/client@2.0.0-beta.67": + version "2.0.0-beta.67" + resolved "https://registry.yarnpkg.com/@vuepress/client/-/client-2.0.0-beta.67.tgz#7cb444eaa12032a7d07b8d59a515d291933518dc" + integrity sha512-xfXZXmZmMbCvQxUhNltuAZzpoiwM0x9ke+DdPPDBF0oGMNDlmtOlsD7NcH322vQE3ehYy5mXJttXuEmfoNOG6A== + dependencies: + "@vue/devtools-api" "^6.5.0" + "@vuepress/shared" "2.0.0-beta.67" + "@vueuse/core" "^10.4.1" + vue "^3.3.4" + vue-router "^4.2.4" + "@vuepress/core@2.0.0-beta.66": version "2.0.0-beta.66" resolved "https://registry.yarnpkg.com/@vuepress/core/-/core-2.0.0-beta.66.tgz#c574df2765d0b56a1bb6fd41417a981ab088c112" @@ -597,6 +608,17 @@ "@vuepress/utils" "2.0.0-beta.66" vue "^3.3.4" +"@vuepress/core@2.0.0-beta.67": + version "2.0.0-beta.67" + resolved "https://registry.yarnpkg.com/@vuepress/core/-/core-2.0.0-beta.67.tgz#925eac48fdc27855a9e75b46c23c6dd37a1c2e4c" + integrity sha512-pbCm1x+zFKZqpJjS68sv3ziEQLMn0KM04Q6W249stcTUUBrKox2OPx+OcX/BrN6yH60OviXN8hD6MgCnFSWdZA== + dependencies: + "@vuepress/client" "2.0.0-beta.67" + "@vuepress/markdown" "2.0.0-beta.67" + "@vuepress/shared" "2.0.0-beta.67" + "@vuepress/utils" "2.0.0-beta.67" + vue "^3.3.4" + "@vuepress/markdown@2.0.0-beta.66": version "2.0.0-beta.66" resolved "https://registry.yarnpkg.com/@vuepress/markdown/-/markdown-2.0.0-beta.66.tgz#73cb75810b776855658a5beaf823f21e907fa982" @@ -619,6 +641,28 @@ markdown-it-emoji "^2.0.2" mdurl "^1.0.1" +"@vuepress/markdown@2.0.0-beta.67": + version "2.0.0-beta.67" + resolved "https://registry.yarnpkg.com/@vuepress/markdown/-/markdown-2.0.0-beta.67.tgz#179f1bbe57a590da362358c8ccad1198875db77a" + integrity sha512-dwciE7dbfDruLan+w9x/LUl5dLdBWB39QXznX/Hhv4oPp+Mm4as53J58gqjuRPi6N25DfRi3ODrzjG5Lduwnfw== + dependencies: + "@mdit-vue/plugin-component" "^0.12.1" + "@mdit-vue/plugin-frontmatter" "^0.12.1" + "@mdit-vue/plugin-headers" "^0.12.1" + "@mdit-vue/plugin-sfc" "^0.12.1" + "@mdit-vue/plugin-title" "^0.12.1" + "@mdit-vue/plugin-toc" "^0.12.1" + "@mdit-vue/shared" "^0.12.1" + "@mdit-vue/types" "^0.12.0" + "@types/markdown-it" "^13.0.1" + "@types/markdown-it-emoji" "^2.0.2" + "@vuepress/shared" "2.0.0-beta.67" + "@vuepress/utils" "2.0.0-beta.67" + markdown-it "^13.0.1" + markdown-it-anchor "^8.6.7" + markdown-it-emoji "^2.0.2" + mdurl "^1.0.1" + "@vuepress/plugin-active-header-links@2.0.0-beta.66": version "2.0.0-beta.66" resolved "https://registry.yarnpkg.com/@vuepress/plugin-active-header-links/-/plugin-active-header-links-2.0.0-beta.66.tgz#eac34e0ee378173fd0c4a334f582716f3fbbe82d" @@ -693,14 +737,14 @@ "@vuepress/utils" "2.0.0-beta.66" execa "^7.1.1" -"@vuepress/plugin-google-analytics@2.0.0-beta.66": - version "2.0.0-beta.66" - resolved "https://registry.yarnpkg.com/@vuepress/plugin-google-analytics/-/plugin-google-analytics-2.0.0-beta.66.tgz#92fc06f326359a3e81e549d46eca19456790e26e" - integrity sha512-RkesQtJtjIi3SczbkBbzJjHM9j85kB5OI3kiXP0K1GOAJk8Nx0vWvZSUyqn8dhjiYsZ2e/gCDZIfhUUpEPN6qg== +"@vuepress/plugin-google-analytics@2.0.0-beta.67": + version "2.0.0-beta.67" + resolved "https://registry.yarnpkg.com/@vuepress/plugin-google-analytics/-/plugin-google-analytics-2.0.0-beta.67.tgz#a05b1dcdf166d2623e2ccc1bab2a39314f7036d3" + integrity sha512-Mffhzhq5tYUq9gRYzpl09NMIQ73MFuN2oIu6SuVPjYtEvKfccdkSksaSuMz0WCmDwTywxFj6v/d3OWjAZ4IFIA== dependencies: - "@vuepress/client" "2.0.0-beta.66" - "@vuepress/core" "2.0.0-beta.66" - "@vuepress/utils" "2.0.0-beta.66" + "@vuepress/client" "2.0.0-beta.67" + "@vuepress/core" "2.0.0-beta.67" + "@vuepress/utils" "2.0.0-beta.67" "@vuepress/plugin-medium-zoom@2.0.0-beta.66": version "2.0.0-beta.66" @@ -761,6 +805,14 @@ "@mdit-vue/types" "^0.12.0" "@vue/shared" "^3.3.4" +"@vuepress/shared@2.0.0-beta.67": + version "2.0.0-beta.67" + resolved "https://registry.yarnpkg.com/@vuepress/shared/-/shared-2.0.0-beta.67.tgz#fb9abc662904117a97c26004aa436f1f2aa02263" + integrity sha512-gm8/6oAnd0Jh8g9xB89S+g8XJxt30QmeXK79J2Nwcbgy88CZnYbZssU1noyxFt4cHDX8wpUf8V5I388/dfHfoQ== + dependencies: + "@mdit-vue/types" "^0.12.0" + "@vue/shared" "^3.3.4" + "@vuepress/theme-default@2.0.0-beta.66": version "2.0.0-beta.66" resolved "https://registry.yarnpkg.com/@vuepress/theme-default/-/theme-default-2.0.0-beta.66.tgz#145b452d71db75dd162297abce89ff930a9c2c08" @@ -803,29 +855,46 @@ picocolors "^1.0.0" upath "^2.0.1" -"@vueuse/core@^10.2.1": - version "10.3.0" - resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-10.3.0.tgz#b2dab7821ef206811b925fc935163c38056fd82b" - integrity sha512-BEM5yxcFKb5btFjTSAFjTu5jmwoW66fyV9uJIP4wUXXU8aR5Hl44gndaaXp7dC5HSObmgbnR2RN+Un1p68Mf5Q== +"@vuepress/utils@2.0.0-beta.67": + version "2.0.0-beta.67" + resolved "https://registry.yarnpkg.com/@vuepress/utils/-/utils-2.0.0-beta.67.tgz#16bcc4bb5a3db270f205ca7b809c178d6774d9fa" + integrity sha512-wCK0uggm4gXroy7UkS1u8wDQmD4b0L6Gjqd/1PZTDhNlMLsrjBx7lqqoIKqarMdB2wmDLroPJcC9otvCz2oQug== + dependencies: + "@types/debug" "^4.1.8" + "@types/fs-extra" "^11.0.1" + "@types/hash-sum" "^1.0.0" + "@vuepress/shared" "2.0.0-beta.67" + debug "^4.3.4" + fs-extra "^11.1.1" + globby "^13.2.2" + hash-sum "^2.0.0" + ora "^7.0.1" + picocolors "^1.0.0" + upath "^2.0.1" + +"@vueuse/core@^10.2.1", "@vueuse/core@^10.4.1": + version "10.4.1" + resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-10.4.1.tgz#fc2c8a83a571c207aaedbe393b22daa6d35123f2" + integrity sha512-DkHIfMIoSIBjMgRRvdIvxsyboRZQmImofLyOHADqiVbQVilP8VVHDhBX2ZqoItOgu7dWa8oXiNnScOdPLhdEXg== dependencies: "@types/web-bluetooth" "^0.0.17" - "@vueuse/metadata" "10.3.0" - "@vueuse/shared" "10.3.0" + "@vueuse/metadata" "10.4.1" + "@vueuse/shared" "10.4.1" vue-demi ">=0.14.5" -"@vueuse/metadata@10.3.0": - version "10.3.0" - resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-10.3.0.tgz#14fe6cc909573785f73a56e4d9351edf3830b796" - integrity sha512-Ema3YhNOa4swDsV0V7CEY5JXvK19JI/o1szFO1iWxdFg3vhdFtCtSTP26PCvbUpnUtNHBY2wx5y3WDXND5Pvnw== +"@vueuse/metadata@10.4.1": + version "10.4.1" + resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-10.4.1.tgz#9d2ff5c67abf17a8c07865c2413fbd0e92f7b7d7" + integrity sha512-2Sc8X+iVzeuMGHr6O2j4gv/zxvQGGOYETYXEc41h0iZXIRnRbJZGmY/QP8dvzqUelf8vg0p/yEA5VpCEu+WpZg== -"@vueuse/shared@10.3.0": - version "10.3.0" - resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-10.3.0.tgz#ce6b4b6860e14aaa293025dcf0cbe1036a25869f" - integrity sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg== +"@vueuse/shared@10.4.1": + version "10.4.1" + resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-10.4.1.tgz#d5ce33033c156efb60664b5d6034d6cd4e2f530c" + integrity sha512-vz5hbAM4qA0lDKmcr2y3pPdU+2EVw/yzfRsBdu+6+USGa4PxqSQRYIUC9/NcT06y+ZgaTsyURw2I9qOFaaXHAg== dependencies: vue-demi ">=0.14.5" -algoliasearch@^4.0.0: +algoliasearch@^4.19.1: version "4.19.1" resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.19.1.tgz#18111fb422eaf841737adb92d5ab12133d244218" integrity sha512-IJF5b93b2MgAzcE/tuzW0yOPnuUyRgGAtaPv5UUywXM8kzqfdwZTO4sPJBzoGz1eOy6H9uEchsJsBFTELZSu+g== @@ -932,11 +1001,11 @@ cac@^6.7.14: integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001520: - version "1.0.30001520" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001520.tgz#62e2b7a1c7b35269594cf296a80bdf8cb9565006" - integrity sha512-tahF5O9EiiTzwTUqAeFjIZbn4Dnqxzz7ktrgGlMYNLH43Ul26IgTMH/zvL3DG0lZxBYnlT04axvInszUsZULdA== + version "1.0.30001532" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz#c6a4d5d2da6d2b967f0ee5e12e7f680db6ad2fca" + integrity sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw== -chalk@^5.0.0: +chalk@^5.0.0, chalk@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== @@ -963,7 +1032,7 @@ cli-cursor@^4.0.0: dependencies: restore-cursor "^4.0.0" -cli-spinners@^2.6.1: +cli-spinners@^2.6.1, cli-spinners@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.0.tgz#5881d0ad96381e117bbe07ad91f2008fe6ffd8db" integrity sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g== @@ -1013,10 +1082,20 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + electron-to-chromium@^1.4.477: - version "1.4.490" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz#d99286f6e915667fa18ea4554def1aa60eb4d5f1" - integrity sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A== + version "1.4.513" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz#41a50bf749aa7d8058ffbf7a131fc3327a7b1675" + integrity sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw== + +emoji-regex@^10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.2.1.tgz#a41c330d957191efd3d9dfe6e1e8e1e9ab048b3f" + integrity sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA== entities@~3.0.1: version "3.0.1" @@ -1119,9 +1198,9 @@ fill-range@^7.0.1: to-regex-range "^5.0.1" fraction.js@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" - integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== + version "4.3.6" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.6.tgz#e9e3acec6c9a28cf7bc36cbe35eea4ceb2c5c92d" + integrity sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg== fs-extra@^11.1.1: version "11.1.1" @@ -1133,9 +1212,9 @@ fs-extra@^11.1.1: universalify "^2.0.0" fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== get-stream@^6.0.1: version "6.0.1" @@ -1196,9 +1275,9 @@ ignore@^5.2.4: integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== immutable@^4.0.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.2.tgz#f89d910f8dfb6e15c03b2cae2faaf8c1f66455fe" - integrity sha512-oGXzbEDem9OOpDWZu88jGiYCvIsLHMvGw+8OXlpsvTFvIQplQbjg1B1cvKg8f7Hoch6+NGjpPsH1Fr+Mc2D1aA== + version "4.3.4" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.4.tgz#2e07b33837b4bb7662f288c244d1ced1ef65a78f" + integrity sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA== inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" @@ -1244,7 +1323,7 @@ is-stream@^3.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== -is-unicode-supported@^1.1.0: +is-unicode-supported@^1.1.0, is-unicode-supported@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz#d824984b616c292a2e198207d4a609983842f714" integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ== @@ -1297,9 +1376,9 @@ log-symbols@^5.1.0: is-unicode-supported "^1.1.0" magic-string@^0.30.0: - version "0.30.2" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.2.tgz#dcf04aad3d0d1314bc743d076c50feb29b3c7aca" - integrity sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug== + version "0.30.3" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.3.tgz#403755dfd9d6b398dfa40635d52e96c5ac095b85" + integrity sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw== dependencies: "@jridgewell/sourcemap-codec" "^1.4.15" @@ -1433,6 +1512,21 @@ ora@^6.3.1: strip-ansi "^7.0.1" wcwidth "^1.0.1" +ora@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-7.0.1.tgz#cdd530ecd865fe39e451a0e7697865669cb11930" + integrity sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw== + dependencies: + chalk "^5.3.0" + cli-cursor "^4.0.0" + cli-spinners "^2.9.0" + is-interactive "^2.0.0" + is-unicode-supported "^1.3.0" + log-symbols "^5.1.0" + stdin-discarder "^0.1.0" + string-width "^6.1.0" + strip-ansi "^7.1.0" + path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -1472,18 +1566,18 @@ postcss-value-parser@^4.2.0: integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== postcss@^8.1.10, postcss@^8.4.25, postcss@^8.4.27: - version "8.4.27" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.27.tgz#234d7e4b72e34ba5a92c29636734349e0d9c3057" - integrity sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ== + version "8.4.29" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.29.tgz#33bc121cf3b3688d4ddef50be869b2a54185a1dd" + integrity sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw== dependencies: nanoid "^3.3.6" picocolors "^1.0.0" source-map-js "^1.0.2" preact@^10.0.0: - version "10.16.0" - resolved "https://registry.yarnpkg.com/preact/-/preact-10.16.0.tgz#68a06d70b191b8a313ea722d61e09c6b2a79a37e" - integrity sha512-XTSj3dJ4roKIC93pald6rWuB2qQJO9gO2iLLyTe87MrjQN+HklueLsmskbywEWqCHlclgz3/M4YLL2iBr9UmMA== + version "10.17.1" + resolved "https://registry.yarnpkg.com/preact/-/preact-10.17.1.tgz#0a1b3c658c019e759326b9648c62912cf5c2dde1" + integrity sha512-X9BODrvQ4Ekwv9GURm9AKAGaomqXmip7NQTZgY7gcNmr7XE83adOMJvd3N42id1tMFU7ojiynRsYnY6/BRFxLA== prismjs@^1.29.0: version "1.29.0" @@ -1525,9 +1619,9 @@ reusify@^1.0.4: integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== rollup@^3.26.2, rollup@^3.27.1: - version "3.28.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.28.0.tgz#a3c70004b01934760c0cb8df717c7a1d932389a2" - integrity sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw== + version "3.29.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.1.tgz#ba53a179d46ac3cd79e162dca6ab70d93cd26f78" + integrity sha512-c+ebvQz0VIH4KhhCpDsI+Bik0eT8ZFEVZEYw0cGMVqIP8zc+gnwl7iXCamTw7vzv2MeuZFZfdx5JJIq+ehzDlg== optionalDependencies: fsevents "~2.3.2" @@ -1551,9 +1645,9 @@ sass-loader@^13.3.2: neo-async "^2.6.2" sass@^1.63.6: - version "1.65.1" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.65.1.tgz#8f283b0c26335a88246a448d22e1342ba2ea1432" - integrity sha512-9DINwtHmA41SEd36eVPQ9BJKpn7eKDQmUHmpI0y5Zv2Rcorrh0zS+cFrt050hdNbmmCNKTW3hV5mWfuegNRsEA== + version "1.66.1" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.66.1.tgz#04b51c4671e4650aa393740e66a4e58b44d055b1" + integrity sha512-50c+zTsZOJVgFfTgwwEzkjA3/QACgdNsKueWPyAR0mRINIvLAStVQBbPg14iuqEQ74NPDbXzJARJ/O4SI1zftA== dependencies: chokidar ">=3.0.0 <4.0.0" immutable "^4.0.0" @@ -1606,6 +1700,15 @@ stdin-discarder@^0.1.0: dependencies: bl "^5.0.0" +string-width@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-6.1.0.tgz#96488d6ed23f9ad5d82d13522af9e4c4c3fd7518" + integrity sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^10.2.1" + strip-ansi "^7.0.1" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -1613,7 +1716,7 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -strip-ansi@^7.0.1: +strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== @@ -1682,9 +1785,9 @@ vite@~4.4.2: fsevents "~2.3.2" vue-demi@>=0.14.5: - version "0.14.5" - resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.5.tgz#676d0463d1a1266d5ab5cba932e043d8f5f2fbd9" - integrity sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA== + version "0.14.6" + resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.6.tgz#dc706582851dc1cdc17a0054f4fec2eb6df74c92" + integrity sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w== vue-router@^4.2.4: version "4.2.4" @@ -1737,6 +1840,6 @@ which@^2.0.1: isexe "^2.0.0" yaml@^2.1.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" - integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== + version "2.3.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.2.tgz#f522db4313c671a0ca963a75670f1c12ea909144" + integrity sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==