diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 4b403d4fce..8ca42d1d5d 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -31,27 +31,29 @@ }, packageRules: [ { - "matchFileNames": ["package.json"], - "enabled": false + matchFileNames: [ + 'package.json', + ], + enabled: false, }, { matchFileNames: [ 'testing/**', ], - matchPackagePatterns: [ - 'conftest', - ], additionalBranchPrefix: '{{packageFileDir}}-', groupName: 'conftest-testing', + matchPackageNames: [ + '/conftest/', + ], }, { ignorePaths: [ 'testing/**', ], - matchPackagePatterns: [ - 'github-actions', - ], groupName: 'github-', + matchPackageNames: [ + '/github-actions/', + ], }, { matchDatasources: [ @@ -69,7 +71,7 @@ 'golang', ], versioning: 'go', - groupName: 'go' + groupName: 'go', }, ], customManagers: [ @@ -85,7 +87,7 @@ // ENV DEFAULT_TERRAFORM_VERSION=x.x.x // # renovate: datasource=github-releases depName=open-policy-agent/conftest // ARG DEFAULT_CONFTEST_VERSION=x.x.x - "renovate: datasource=(?.*?) depName=(?.*?)( versioning=(?.*?))?\\s(ARG|ENV) .*?_VERSION=(?.*)\\s", + 'renovate: datasource=(?.*?) depName=(?.*?)( versioning=(?.*?))?\\s(ARG|ENV) .*?_VERSION=(?.*)\\s', ], versioningTemplate: '{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}', extractVersionTemplate: '^v(?\\d+\\.\\d+\\.\\d+)', diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d24fde5db6..03d6f99ff2 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -71,7 +71,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3 + uses: github/codeql-action/init@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -85,7 +85,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3 + uses: github/codeql-action/autobuild@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3 # ℹī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -98,7 +98,7 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3 + uses: github/codeql-action/analyze@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 124d8a860c..8d0610207d 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,7 +9,7 @@ on: - ready_for_review branches: - "main" - - 'release-**' + - "release-**" concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} @@ -47,18 +47,18 @@ jobs: name: Linting runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 - # need to setup go toolchain explicitly - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5 - with: - go-version-file: go.mod + # need to setup go toolchain explicitly + - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5 + with: + go-version-file: go.mod - - name: golangci-lint - uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 # v6 - with: - # renovate: datasource=github-releases depName=golangci/golangci-lint - version: v1.59.1 + - name: golangci-lint + uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 # v6 + with: + # renovate: datasource=github-releases depName=golangci/golangci-lint + version: v1.60.1 skip-lint: needs: [changes] diff --git a/.github/workflows/pr-size-labeler.yml b/.github/workflows/pr-size-labeler.yml index d652c0ef8c..44900a8aa1 100644 --- a/.github/workflows/pr-size-labeler.yml +++ b/.github/workflows/pr-size-labeler.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest name: Label the PR size steps: - - uses: codelytv/pr-size-labeler@56f6f0fc35c7cc0f72963b8467729e1120cb4bed # v1 + - uses: codelytv/pr-size-labeler@c7a55a022747628b50f3eb5bf863b9e796b8f274 # v1 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} xs_label: 'size/xs' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f1d820fceb..7a15dd80ed 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,7 +42,7 @@ jobs: if: needs.changes.outputs.should-run-tests == 'true' name: Tests runs-on: ubuntu-24.04 - container: ghcr.io/runatlantis/testing-env:latest@sha256:c2753685ecfb321a00ac3e0deb64bb7944cdffa06870f8533d839b4efc08e1d5 + container: ghcr.io/runatlantis/testing-env:latest@sha256:eeb4c08aa2c7f27c4cfef089fafd6404ce806d77452d5ad3010bb3ca0e573538 steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 @@ -59,7 +59,7 @@ jobs: ########################################################### - name: Slack failure notification if: ${{ github.ref == 'refs/heads/main' && failure() }} - uses: slackapi/slack-github-action@70cd7be8e40a46e8b0eced40b0de447bdb42f68e # v1.26.0 + uses: slackapi/slack-github-action@37ebaef184d7626c5f204ab8d3baff4262dd30f0 # v1.27.0 with: payload: | { @@ -121,7 +121,44 @@ jobs: # We do this instead of setting --default-tf-version because setting # that flag starts the download asynchronously so we'd have a race # condition. - - uses: hashicorp/setup-terraform@651471c36a6092792c552e8b1bef71e592b462d8 # v3 + - uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3 + with: + terraform_version: ${{ env.TERRAFORM_VERSION }} + + - name: Setup ngrok + run: | + wget -q -O ngrok.tar.gz https://bin.equinox.io/a/4no1PS1PoRF/ngrok-v3-3.13.0-linux-amd64.tar.gz + tar -xzf ngrok.tar.gz + chmod +x ngrok + ./ngrok version + - name: Setup gitconfig + run: | + git config --global user.email "maintainers@runatlantis.io" + git config --global user.name "atlantisbot" + + - run: | + make build-service + ./scripts/e2e.sh + e2e-gitlab: + runs-on: ubuntu-latest + # dont run e2e tests on forked PRs + if: github.event.pull_request.head.repo.fork == false + env: + TERRAFORM_VERSION: 1.9.2 + ATLANTIS_GITLAB_USER: ${{ secrets.ATLANTISBOT_GITLAB_USERNAME }} + ATLANTIS_GITLAB_TOKEN: ${{ secrets.ATLANTISBOT_GITLAB_TOKEN }} + NGROK_AUTH_TOKEN: ${{ secrets.ATLANTISBOT_NGROK_AUTH_TOKEN }} + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5 + with: + go-version-file: go.mod + + # This version of TF will be downloaded before Atlantis is started. + # We do this instead of setting --default-tf-version because setting + # that flag starts the download asynchronously so we'd have a race + # condition. + - uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3 with: terraform_version: ${{ env.TERRAFORM_VERSION }} diff --git a/.node-version b/.node-version index 8ce7030825..3516580bbb 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -20.16.0 +20.17.0 diff --git a/.tool-versions b/.tool-versions index 20e3a2a6db..61fe7092be 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ node 20.14.0 -go 1.22.5 +go 1.23.0 diff --git a/Dockerfile b/Dockerfile index 8f33eb8b4e..92d7e67fe0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,13 @@ # syntax=docker/dockerfile:1@sha256:fe40cf4e92cd0c467be2cfc30657a680ae2398318afd50b0c80585784c604f28 # what distro is the image being built for ARG ALPINE_TAG=3.20.2@sha256:0a4eaa0eecf5f8c050e5bba433f58c052be7587ee8af3e8b3910ef9ab5fbe9f5 -ARG DEBIAN_TAG=12.6-slim@sha256:5f7d5664eae4a192c2d2d6cb67fc3f3c7891a8722cd2903cc35aa649a12b0c8d -ARG GOLANG_TAG=1.22.5-alpine@sha256:0d3653dd6f35159ec6e3d10263a42372f6f194c3dea0b35235d72aabde86486e +ARG DEBIAN_TAG=12.6-slim@sha256:2ccc7e39b0a6f504d252f807da1fc4b5bcd838e83e4dec3e2f57b2a4a64e7214 +ARG GOLANG_TAG=1.23.0-alpine@sha256:d0b31558e6b3e4cc59f6011d79905835108c919143ebecc58f35965bf79948f4 # renovate: datasource=github-releases depName=hashicorp/terraform versioning=hashicorp -ARG DEFAULT_TERRAFORM_VERSION=1.9.3 +ARG DEFAULT_TERRAFORM_VERSION=1.9.5 # renovate: datasource=github-releases depName=opentofu/opentofu versioning=hashicorp -ARG DEFAULT_OPENTOFU_VERSION=1.7.3 +ARG DEFAULT_OPENTOFU_VERSION=1.8.1 # renovate: datasource=github-releases depName=open-policy-agent/conftest ARG DEFAULT_CONFTEST_VERSION=0.55.0 diff --git a/Dockerfile.dev b/Dockerfile.dev index 31f072c7e1..41252bce0f 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,3 +1,3 @@ -FROM ghcr.io/runatlantis/atlantis:latest@sha256:52ee7c47f37a56fa82c26d2931d5d1d67f9f2d16f81c65e46c02a7b10de9f642 +FROM ghcr.io/runatlantis/atlantis:latest@sha256:83c7c8ef53937648ff34b956b32f02b78b7dc56b53575f610689174198c5abc1 COPY atlantis /usr/local/bin/atlantis WORKDIR /atlantis/src diff --git a/GOVERNANCE.md b/GOVERNANCE.md deleted file mode 100644 index 9b4454e111..0000000000 --- a/GOVERNANCE.md +++ /dev/null @@ -1,116 +0,0 @@ -# Atlantis Governance - -This document defines the project governance for Atlantis. - -## Overview - -**Atlantis** is committed to building an open, inclusive, productive and self-governing open source -community focused on building a high-quality infrastructure orchestration system. The -community is governed by this document with the goal of defining how community -should work together to achieve this goal. - -## Code Repositories - -The following code repositories are governed by Atlantis community and -maintained under the `runatlantis` organization. - -* **[atlantis](https://github.com/runatlantis/atlantis):** Main Atlantis codebase. -* **[atlantis-helm-charts](https://github.com/runatlantis/helm-charts):** Helm chart for easy deployment of Atlantis. -* **[atlantis-tests](https://github.com/runatlantis/atlantis-tests):** A set of terraform projects that atlantis e2e tests run on. -* **[atlantis-example](https://github.com/runatlantis/atlantis-example):** A simple terraform project to use along with atlantis bootstrap mode. - -## Community Roles - -* **Users:** Members that engage with the Atlantis community via any medium (Slack, GitHub, mailing lists, etc.). -* **Contributors:** Regular contributions to projects (documentation, code reviews, responding to issues, participation in proposal discussions, contributing code, etc.). -* **Core Contributors:** Contributors who drive certain subprojects within Atlantis. They are responsible for the direction and work done within that subproject, providing enhancements and support for the Atlantis project as a whole. Core Contributors are expected to contribute code and documentation, review PRs including ensuring quality of code, triage issues, proactively fix bugs, and perform maintenance tasks for the subprojects they are responsible for. -* **Maintainers:** The Atlantis project leaders. They are responsible for the overall health and direction of the project; final reviewers of PRs and responsible for releases. Some Maintainers are responsible for one or more components within a project, acting as technical leads for that component. Maintainers are expected to contribute code and documentation, review PRs including ensuring quality of code, triage issues, proactively fix bugs, and perform maintenance tasks for these components. - -### Maintainers - -New maintainers and subproject maintainers must be nominated by an existing maintainer and must be elected by a supermajority of existing maintainers. Likewise, maintainers can be removed by a supermajority of the existing maintainers or can resign by notifying one of the maintainers. - -### Supermajority - -A supermajority is defined as two-thirds of members in the group. -A supermajority of [Maintainers](#maintainers) is required for certain -decisions as outlined above. Voting on decisions can happen on the mailing list, GitHub, Slack, email, or via a voting service, when appropriate. Maintainers can either vote "agree, yes, +1", "disagree, no, -1", or "abstain". A vote passes when supermajority is met. An abstain vote equals not voting at all. - -### Decision Making - -Ideally, all project decisions are resolved by consensus. If impossible, any -maintainer may call a vote. Unless otherwise specified in this document, any -vote will be decided by a supermajority of maintainers. - -Votes by maintainers belonging to the same company -will count as one vote; e.g., 4 maintainers employed by fictional company **Fictiousum** will -only have **one** combined vote. If voting members from a given company do not -agree, the company's vote is determined by a supermajority of voters from that -company. If no supermajority is achieved, the company is considered to have -abstained. - -## Proposal Process - -One of the most important aspects in any open source community is the concept -of proposals. Large changes to the codebase and/or new features should be -preceded by a proposal as an ADR or GH issue in the main Atlantis repo. This process allows for all -members of the community to weigh in on the concept (including the technical -details), share their comments and ideas, and offer to help. It also ensures -that members are not duplicating work or inadvertently stepping on toes by -making large conflicting changes. - -The project roadmap is defined by accepted proposals. - -Proposals should cover the high-level objectives, use cases, and technical -recommendations on how to implement. In general, the community member(s) -interested in implementing the proposal should be either deeply engaged in the -proposal process or be an author of the proposal. - -The proposal should be documented as a separated markdown file pushed to the root of the -`docs/adr` folder in the [atlantis](https://github.com/runatlantis/atlantis) -repository via PR. The name of the file should follow the name pattern set by the ADR process `<####-short -meaningful words joined by '-'>.md`, e.g: -`0002-adr-proposal.md`. - -Use the [ADR Tools](https://github.com/npryce/adr-tools) and run `adr new ` - -### Proposal Lifecycle - -The proposal PR can be marked with different status labels to represent the -status of the proposal: - -* **New**: Proposal is just created. -* **Reviewing**: Proposal is under review and discussion. -* **Accepted**: Proposal is reviewed and accepted (either by consensus or vote). -* **Rejected**: Proposal is reviewed and rejected (either by consensus or vote). - -## Lazy Consensus - -To maintain velocity in a project as busy as Atlantis, the concept of [Lazy -Consensus](http://en.osswiki.info/concepts/lazy_consensus) is practiced. Ideas -and/or proposals should be shared by maintainers via -GitHub with the appropriate maintainer groups (e.g., -`@atlantis/all-maintainers`) tagged. Out of respect for other contributors, -major changes should also be accompanied by a ping on Slack in the -[#contributors](https://atlantis-community.slack.com/archives/C04ES70Q6E8) channel or a note on the -Atlantis google mailing list as appropriate. Author(s) of proposal, Pull Requests, -issues, etc. will give a time period of no less than five (5) working days for -comment and remain cognizant of popular observed world holidays. - -Other maintainers may chime in and request additional time for review, but -should remain cognizant of blocking progress and abstain from delaying -progress unless absolutely needed. The expectation is that blocking progress -is accompanied by a guarantee to review and respond to the relevant action(s) -(proposals, PRs, issues, etc.) in short order. - -Lazy Consensus is practiced for all projects in the `runatlantis` org, including -the main project repository, community-driven sub-projects, and the community -repo that includes proposals and governing documents. - -Lazy consensus does _not_ apply to the process of: - -* Removal of maintainers from Atlantis - -## Updating Governance - -All substantive changes in Governance require a supermajority agreement by all maintainers. diff --git a/e2e/e2e.go b/e2e/e2e.go index 5c19d501b0..079c329df2 100644 --- a/e2e/e2e.go +++ b/e2e/e2e.go @@ -114,7 +114,12 @@ func (t *E2ETester) Start(ctx context.Context) (*E2EResult, error) { log.Printf("created pull request %s", url) // defer closing pull request and delete remote branch - defer cleanUp(ctx, t, pullId, branchName) // nolint: errcheck + defer func() { + err := cleanUp(ctx, t, pullId, branchName) + if err != nil { + log.Printf("Failed to cleanup: %v", err) + } + }() // wait for atlantis to respond to webhook and autoplan. time.Sleep(2 * time.Second) @@ -123,7 +128,7 @@ func (t *E2ETester) Start(ctx context.Context) (*E2EResult, error) { // waiting for atlantis run and finish maxLoops := 20 i := 0 - for ; i < maxLoops && checkStatus(state); i++ { + for ; i < maxLoops && t.vcsClient.IsAtlantisInProgress(state); i++ { time.Sleep(2 * time.Second) state, _ = t.vcsClient.GetAtlantisStatus(ctx, branchName) if state == "" { @@ -139,22 +144,13 @@ func (t *E2ETester) Start(ctx context.Context) (*E2EResult, error) { log.Printf("atlantis run finished with status %q", state) e2eResult.testResult = state // check if atlantis run was a success - if state != "success" { + if !t.vcsClient.DidAtlantisSucceed(state) { return e2eResult, fmt.Errorf("atlantis run project type %q failed with %q status", t.projectType.Name, state) } return e2eResult, nil } -func checkStatus(state string) bool { - for _, s := range []string{"success", "error", "failure"} { - if state == s { - return false - } - } - return true -} - func cleanUp(ctx context.Context, t *E2ETester, pullRequestNumber int, branchName string) error { // clean up err := t.vcsClient.ClosePullRequest(ctx, pullRequestNumber) @@ -163,12 +159,11 @@ func cleanUp(ctx context.Context, t *E2ETester, pullRequestNumber int, branchNam } log.Printf("closed pull request %d", pullRequestNumber) - deleteBranchName := fmt.Sprintf("%s/%s", "heads", branchName) - err = t.vcsClient.DeleteBranch(ctx, deleteBranchName) + err = t.vcsClient.DeleteBranch(ctx, branchName) if err != nil { - return fmt.Errorf("error while deleting branch %s: %v", deleteBranchName, err) + return fmt.Errorf("error while deleting branch %s: %v", branchName, err) } - log.Printf("deleted branch %s", deleteBranchName) + log.Printf("deleted branch %s", branchName) return nil } diff --git a/e2e/github.go b/e2e/github.go index 40b64f7efd..06cc2ebbca 100644 --- a/e2e/github.go +++ b/e2e/github.go @@ -153,9 +153,23 @@ func (g GithubClient) ClosePullRequest(ctx context.Context, pullRequestNumber in } func (g GithubClient) DeleteBranch(ctx context.Context, branchName string) error { - _, err := g.client.Git.DeleteRef(ctx, g.ownerName, g.repoName, branchName) + deleteBranchName := fmt.Sprintf("%s/%s", "heads", branchName) + _, err := g.client.Git.DeleteRef(ctx, g.ownerName, g.repoName, deleteBranchName) if err != nil { return fmt.Errorf("error while deleting branch %s: %v", branchName, err) } return nil } + +func (g GithubClient) IsAtlantisInProgress(state string) bool { + for _, s := range []string{"success", "error", "failure"} { + if state == s { + return false + } + } + return true +} + +func (g GithubClient) DidAtlantisSucceed(state string) bool { + return state == "success" +} diff --git a/e2e/gitlab.go b/e2e/gitlab.go new file mode 100644 index 0000000000..2226aa299d --- /dev/null +++ b/e2e/gitlab.go @@ -0,0 +1,181 @@ +// Copyright 2017 HootSuite Media Inc. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Modified hereafter by contributors to runatlantis/atlantis. + +package main + +import ( + "context" + "fmt" + "log" + "os" + "os/exec" + + "github.com/xanzy/go-gitlab" +) + +type GitlabClient struct { + client *gitlab.Client + username string + ownerName string + repoName string + token string + projectId int + // A mapping from branch names to MR IDs + branchToMR map[string]int +} + +func NewGitlabClient() *GitlabClient { + + gitlabUsername := os.Getenv("ATLANTIS_GITLAB_USER") + if gitlabUsername == "" { + log.Fatalf("ATLANTIS_GITLAB_USER cannot be empty") + } + gitlabToken := os.Getenv("ATLANTIS_GITLAB_TOKEN") + if gitlabToken == "" { + log.Fatalf("ATLANTIS_GITLAB_TOKEN cannot be empty") + } + ownerName := os.Getenv("GITLAB_REPO_OWNER_NAME") + if ownerName == "" { + ownerName = "run-atlantis" + } + repoName := os.Getenv("GITLAB_REPO_NAME") + if repoName == "" { + repoName = "atlantis-tests" + } + + gitlabClient, err := gitlab.NewClient(gitlabToken) + if err != nil { + log.Fatalf("Failed to create client: %v", err) + } + project, _, err := gitlabClient.Projects.GetProject(fmt.Sprintf("%s/%s", ownerName, repoName), &gitlab.GetProjectOptions{}) + if err != nil { + log.Fatalf("Failed to find project: %v", err) + } + + return &GitlabClient{ + client: gitlabClient, + username: gitlabUsername, + ownerName: ownerName, + repoName: repoName, + token: gitlabToken, + projectId: project.ID, + branchToMR: make(map[string]int), + } + +} + +func (g GitlabClient) Clone(cloneDir string) error { + + repoURL := fmt.Sprintf("https://%s:%s@gitlab.com/%s/%s.git", g.username, g.token, g.ownerName, g.repoName) + cloneCmd := exec.Command("git", "clone", repoURL, cloneDir) + // git clone the repo + log.Printf("git cloning into %q", cloneDir) + if output, err := cloneCmd.CombinedOutput(); err != nil { + return fmt.Errorf("failed to clone repository: %v: %s", err, string(output)) + } + return nil + +} + +func (g GitlabClient) CreateAtlantisWebhook(ctx context.Context, hookURL string) (int64, error) { + hook, _, err := g.client.Projects.AddProjectHook(g.projectId, &gitlab.AddProjectHookOptions{ + URL: &hookURL, + IssuesEvents: gitlab.Ptr(true), + MergeRequestsEvents: gitlab.Ptr(true), + PushEvents: gitlab.Ptr(true), + }) + if err != nil { + return 0, err + } + log.Printf("created webhook for %s", hook.URL) + return int64(hook.ID), err +} + +func (g GitlabClient) DeleteAtlantisHook(ctx context.Context, hookID int64) error { + _, err := g.client.Projects.DeleteProjectHook(g.projectId, int(hookID)) + if err != nil { + return err + } + log.Printf("deleted webhook id %d", hookID) + return nil +} + +func (g GitlabClient) CreatePullRequest(ctx context.Context, title, branchName string) (string, int, error) { + + mr, _, err := g.client.MergeRequests.CreateMergeRequest(g.projectId, &gitlab.CreateMergeRequestOptions{ + Title: gitlab.Ptr(title), + SourceBranch: gitlab.Ptr(branchName), + TargetBranch: gitlab.Ptr("main"), + }) + if err != nil { + return "", 0, fmt.Errorf("error while creating new pull request: %v", err) + } + g.branchToMR[branchName] = mr.IID + return mr.WebURL, mr.IID, nil + +} + +func (g GitlabClient) GetAtlantisStatus(ctx context.Context, branchName string) (string, error) { + + pipelineInfos, _, err := g.client.MergeRequests.ListMergeRequestPipelines(g.projectId, g.branchToMR[branchName]) + if err != nil { + return "", err + } + // Possible todo: determine which status in the pipeline we care about? + if len(pipelineInfos) != 1 { + return "", fmt.Errorf("unexpected pipelines: %d", len(pipelineInfos)) + } + pipelineInfo := pipelineInfos[0] + pipeline, _, err := g.client.Pipelines.GetPipeline(g.projectId, pipelineInfo.ID) + if err != nil { + return "", err + } + + return pipeline.Status, nil +} + +func (g GitlabClient) ClosePullRequest(ctx context.Context, pullRequestNumber int) error { + // clean up + _, _, err := g.client.MergeRequests.UpdateMergeRequest(g.projectId, pullRequestNumber, &gitlab.UpdateMergeRequestOptions{ + StateEvent: gitlab.Ptr("close"), + }) + if err != nil { + return fmt.Errorf("error while closing new pull request: %v", err) + } + return nil + +} +func (g GitlabClient) DeleteBranch(ctx context.Context, branchName string) error { + _, err := g.client.Branches.DeleteBranch(g.projectId, branchName) + + if err != nil { + return fmt.Errorf("error while deleting branch %s: %v", branchName, err) + } + return nil + +} + +func (g GitlabClient) IsAtlantisInProgress(state string) bool { + // From https://docs.gitlab.com/ee/api/pipelines.html + // created, waiting_for_resource, preparing, pending, running, success, failed, canceled, skipped, manual, scheduled + for _, s := range []string{"success", "failed", "canceled", "skipped"} { + if state == s { + return false + } + } + return true +} + +func (g GitlabClient) DidAtlantisSucceed(state string) bool { + return state == "success" +} diff --git a/e2e/go.mod b/e2e/go.mod index b1d719e5a9..b0cb6ece1e 100644 --- a/e2e/go.mod +++ b/e2e/go.mod @@ -1,13 +1,22 @@ module github.com/runatlantis/atlantis/e2e -go 1.22 +go 1.23.0 require ( github.com/google/go-github/v59 v59.0.0 github.com/hashicorp/go-multierror v1.1.1 + github.com/xanzy/go-gitlab v0.108.0 ) require ( + 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 + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/oauth2 v0.6.0 // indirect + golang.org/x/time v0.3.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.33.0 // indirect ) diff --git a/e2e/go.sum b/e2e/go.sum index 0bb1926922..e7d215d8ca 100644 --- a/e2e/go.sum +++ b/e2e/go.sum @@ -1,4 +1,13 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +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.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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v59 v59.0.0 h1:7h6bgpF5as0YQLLkEiVqpgtJqjimMYhBkD4jT5aN3VA= @@ -8,6 +17,44 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/xanzy/go-gitlab v0.108.0 h1:IEvEUWFR5G1seslRhJ8gC//INiIUqYXuSUoBd7/gFKE= +github.com/xanzy/go-gitlab v0.108.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +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.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/e2e/main.go b/e2e/main.go index 808ca7e9e4..dacee30451 100644 --- a/e2e/main.go +++ b/e2e/main.go @@ -15,6 +15,7 @@ package main import ( "context" + "errors" "log" "os" @@ -34,6 +35,20 @@ type Project struct { ApplyCommand string } +func getVCSClient() (VCSClient, error) { + + if os.Getenv("ATLANTIS_GH_USER") != "" { + log.Print("Running tests for github") + return NewGithubClient(), nil + } + if os.Getenv("ATLANTIS_GITLAB_USER") != "" { + log.Print("Running tests for gitlab") + return NewGitlabClient(), nil + } + + return nil, errors.New("could not determine which vcs client") +} + func main() { atlantisURL := os.Getenv("ATLANTIS_URL") @@ -55,18 +70,21 @@ func main() { log.Fatalf("failed to clean dir %q before cloning, attempting to continue: %v", cloneDirRoot, err) } - githubClient := NewGithubClient() + vcsClient, err := getVCSClient() + if err != nil { + log.Fatalf("failed to get vcs client: %v", err) + } ctx := context.Background() // we create atlantis hook once for the repo, since the atlantis server can handle multiple requests log.Printf("creating atlantis webhook with %s url", atlantisURL) - hookID, err := githubClient.CreateAtlantisWebhook(ctx, atlantisURL) + hookID, err := vcsClient.CreateAtlantisWebhook(ctx, atlantisURL) if err != nil { log.Fatalf("error creating atlantis webhook: %v", err) } // create e2e test e2e := E2ETester{ - vcsClient: githubClient, + vcsClient: vcsClient, hookID: hookID, cloneDirRoot: cloneDirRoot, } diff --git a/e2e/vcs.go b/e2e/vcs.go index 79f3deb419..2648a913fe 100644 --- a/e2e/vcs.go +++ b/e2e/vcs.go @@ -23,4 +23,6 @@ type VCSClient interface { GetAtlantisStatus(ctx context.Context, branchName string) (string, error) ClosePullRequest(ctx context.Context, pullRequestNumber int) error DeleteBranch(ctx context.Context, branchName string) error + IsAtlantisInProgress(state string) bool + DidAtlantisSucceed(state string) bool } diff --git a/go.mod b/go.mod index eba4a1b543..8b5fea197e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/runatlantis/atlantis -go 1.22.5 +go 1.23.0 require ( code.gitea.io/sdk/gitea v0.19.0 @@ -32,30 +32,30 @@ require ( github.com/mitchellh/go-homedir v1.1.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/petergtz/pegomock/v4 v4.1.0 github.com/pkg/errors v0.9.1 - github.com/redis/go-redis/v9 v9.5.4 + github.com/redis/go-redis/v9 v9.6.1 github.com/remeh/sizedwaitgroup v1.0.0 github.com/shurcooL/githubv4 v0.0.0-20240727222349-48295856cce7 - github.com/slack-go/slack v0.12.5 + github.com/slack-go/slack v0.14.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.18.2 + github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 github.com/uber-go/tally/v4 v4.1.10 github.com/urfave/negroni/v3 v3.1.1 - github.com/xanzy/go-gitlab v0.102.0 - go.etcd.io/bbolt v1.3.10 + github.com/xanzy/go-gitlab v0.108.0 + go.etcd.io/bbolt v1.3.11 go.uber.org/zap v1.27.0 - golang.org/x/term v0.21.0 - golang.org/x/text v0.16.0 + golang.org/x/term v0.23.0 + golang.org/x/text v0.17.0 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/agext/levenshtein v1.2.3 github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/hashicorp/hcl/v2 v2.20.1 + github.com/hashicorp/hcl/v2 v2.22.0 github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29 // indirect go.uber.org/atomic v1.11.0 // indirect ) @@ -88,7 +88,7 @@ require ( github.com/google/go-github/v62 v62.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/gorilla/css v1.0.1 // indirect - github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect @@ -96,7 +96,7 @@ require ( github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/klauspost/compress v1.17.0 // indirect + github.com/klauspost/compress v1.17.2 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/magiconair/properties v1.8.7 // indirect @@ -109,7 +109,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/onsi/gomega v1.27.6 // indirect - github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.12.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect @@ -131,12 +131,12 @@ require ( golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/mod v0.19.0 // indirect golang.org/x/net v0.26.0 // indirect - golang.org/x/oauth2 v0.15.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.21.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.23.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect - google.golang.org/appengine v1.6.7 // indirect + google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/go.sum b/go.sum index 2248a14231..a834be1535 100644 --- a/go.sum +++ b/go.sum @@ -139,8 +139,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-ozzo/ozzo-validation v3.6.0+incompatible h1:msy24VGS42fKO9K1vLz82/GeYW1cILu7Nuuj1N3BBkE= github.com/go-ozzo/ozzo-validation v3.6.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= @@ -242,8 +242,9 @@ github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWS github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-getter/v2 v2.2.3 h1:6CVzhT0KJQHqd9b0pK3xSP0CM/Cv+bVhk+jcaRJ2pGk= @@ -266,8 +267,8 @@ github.com/hashicorp/hc-install v0.8.0 h1:LdpZeXkZYMQhoKPCecJHlKvUkQFixN/nvyR1Cd github.com/hashicorp/hc-install v0.8.0/go.mod h1:+MwJYjDfCruSD/udvBmRB22Nlkwwkwf5sAB6uTIhSaU= 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.20.1 h1:M6hgdyz7HYt1UN9e61j+qKJBqR3orTWbI1HKBJEdxtc= -github.com/hashicorp/hcl/v2 v2.20.1/go.mod h1:TZDqQ4kNKCbh1iJp99FdPiUaVDDUPivbqxZulxDYqL4= +github.com/hashicorp/hcl/v2 v2.22.0 h1:hkZ3nCtqeJsDhPRFz5EA9iwcG1hNWGePOTw6oyul12M= +github.com/hashicorp/hcl/v2 v2.22.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA= github.com/hashicorp/terraform-config-inspect v0.0.0-20240801114854-6714b46f5fe4 h1:RwY5HBgtBZ997UtKJAO2Rx+94ETyevwWEVXWx1SL5YY= github.com/hashicorp/terraform-config-inspect v0.0.0-20240801114854-6714b46f5fe4/go.mod h1:Gz/z9Hbn+4KSp8A2FBtNszfLSdT2Tn/uAKGuVqqWmDI= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= @@ -295,8 +296,8 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8 github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= -github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -354,10 +355,10 @@ github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= -github.com/petergtz/pegomock/v4 v4.0.0 h1:BIGMUof4NXc+xBbuFk0VBfK5Ls7DplcP+LWz4hfYWsY= -github.com/petergtz/pegomock/v4 v4.0.0/go.mod h1:Xscaw/kXYcuh9sGsns+If19FnSMMQy4Wz60YJTn3XOU= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/petergtz/pegomock/v4 v4.1.0 h1:Reoy2rlwshuxNaD2ZWp5TrSCrmoFH5SSLHb5U1z2pog= +github.com/petergtz/pegomock/v4 v4.1.0/go.mod h1:Xscaw/kXYcuh9sGsns+If19FnSMMQy4Wz60YJTn3XOU= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -392,8 +393,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.5.4 h1:vOFYDKKVgrI5u++QvnMT7DksSMYg7Aw/Np4vLJLKLwY= -github.com/redis/go-redis/v9 v9.5.4/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= +github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= 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= @@ -420,8 +421,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= -github.com/slack-go/slack v0.12.5 h1:ddZ6uz6XVaB+3MTDhoW04gG+Vc/M/X1ctC+wssy2cqs= -github.com/slack-go/slack v0.12.5/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= +github.com/slack-go/slack v0.14.0 h1:6c0UTfbRnvRssZUsZ2qe0Iu07VAMPjRqOa6oX8ewF4k= +github.com/slack-go/slack v0.14.0/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= @@ -433,12 +434,13 @@ github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= -github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -459,8 +461,8 @@ github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/negroni/v3 v3.1.1 h1:6MS4nG9Jk/UuCACaUlNXCbiKa0ywF9LXz5dGu09v8hw= github.com/urfave/negroni/v3 v3.1.1/go.mod h1:jWvnX03kcSjDBl/ShB0iHvx5uOs7mAzZXW+JvJ5XYAs= -github.com/xanzy/go-gitlab v0.102.0 h1:ExHuJ1OTQ2yt25zBMMj0G96ChBirGYv8U7HyUiYkZ+4= -github.com/xanzy/go-gitlab v0.102.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= +github.com/xanzy/go-gitlab v0.108.0 h1:IEvEUWFR5G1seslRhJ8gC//INiIUqYXuSUoBd7/gFKE= +github.com/xanzy/go-gitlab v0.108.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -471,10 +473,10 @@ github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8= github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= -github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI= -github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= -go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= -go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= +github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= +github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= +go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= +go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -581,8 +583,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 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.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= -golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= 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= @@ -593,8 +595,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -638,13 +640,13 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= 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= @@ -652,9 +654,10 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-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= @@ -729,8 +732,8 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= diff --git a/runatlantis.io/docs/custom-workflows.md b/runatlantis.io/docs/custom-workflows.md index 46e7eee4ee..3d974fa7a9 100644 --- a/runatlantis.io/docs/custom-workflows.md +++ b/runatlantis.io/docs/custom-workflows.md @@ -450,6 +450,63 @@ projects: workflow: production ``` +### Add directory and repo context for aws resources using default tags + +This is only available in AWS provider version [5.62.0](https://github.com/hashicorp/terraform-provider-aws/releases/tag/v5.62.0) and higher. + +This configuration will create the following tags + +* `repository` equal to `github.com/<owner>/<repo>` which can be changed for gitlab or other VCS +* `repository_dir` equal to the relative directory + +Other default variables can be added such as for workspace. See below for more available environment variables. + +```yaml +workflows: + terraform: + plan: + steps: + # These env vars TF_AWS_DEFAULT_TAGS_ will work for aws provider 5.62.0+ + # https://github.com/hashicorp/terraform-provider-aws/releases/tag/v5.62.0 + - &env_default_tags_repository + env: + name: TF_AWS_DEFAULT_TAGS_repository + command: 'echo "github.com/${BASE_REPO_OWNER}/${BASE_REPO_NAME}"' + - &env_default_tags_repository_dir + env: + name: TF_AWS_DEFAULT_TAGS_repository_dir + command: 'echo "${REPO_REL_DIR}"' + apply: + steps: + - *env_default_tags_repository + - *env_default_tags_repository_dir +``` + +NOTE: +- Appending tags to every resource may regenerate data sources such as `aws_iam_policy_document` which will cause many resources to be modified. See known issue in aws provider [#29421](https://github.com/hashicorp/terraform-provider-aws/issues/29421). +- To run a local plan outside of terraform, the same environment variables will need to be created. + + ```bash + tfvars () { + export terraform_repository=$(git config --get remote.origin.url | sed 's,^git@,,g' | tr ':' '/' | sed 's,.git$,,g') + export terraform_repository_dir=$(git rev-parse --show-prefix | sed 's,\/$,,g') + } + export TF_AWS_DEFAULT_TAGS_repository=$terraform_repository + export TF_AWS_DEFAULT_TAGS_repository_dir=$terraform_repository_dir + tfvars + terraform plan + ``` + + If a colon is used in the tag name, use the `env` command instead of `export`. + + ```bash + tfvars + env \ + TF_AWS_DEFAULT_TAGS_org:repository=$terraform_repository \ + TF_AWS_DEFAULT_TAGS_org:repository_dir=$terraform_repository_dir \ + terraform plan + ``` + ## Reference ### Workflow diff --git a/scripts/e2e.sh b/scripts/e2e.sh index e7d816d4c5..8e531d9563 100755 --- a/scripts/e2e.sh +++ b/scripts/e2e.sh @@ -2,20 +2,67 @@ set -euo pipefail IFS=$'\n\t' +ATLANTIS_PID="" +NGROK_PID="" + +function cleanup() { + cleanupPid "$ATLANTIS_PID" + cleanupPid "$NGROK_PID" +} + +function cleanupPid() { + local pid="$1" + # Never set, no need to clean up + if [[ "$pid" == "" ]] + then + return + fi + # Somehow pid was not number, just being careful + if ! [[ "$pid" =~ ^[0-9]+$ ]] + then + return + fi + # Not currently running, no need to kill + if ! ps -p "$pid" &>/dev/null + then + return + fi + kill $pid +} + # start atlantis server in the background and wait for it to start +# It's the responsibility of the caller of this script to set the github, gitlab, etc. +# permissions via environment variable ./atlantis server \ --data-dir="/tmp" \ --log-level="debug" \ - --repo-allowlist="github.com/runatlantis/atlantis-tests" \ + --repo-allowlist="github.com/runatlantis/atlantis-tests,gitlab.com/run-atlantis/atlantis-tests" \ --repo-config-json='{"repos":[{"id":"/.*/", "allowed_overrides":["apply_requirements","workflow"], "allow_custom_workflows":true}]}' \ &> /tmp/atlantis-server.log & +ATLANTIS_PID=$! sleep 2 +if ! ps -p "$ATLANTIS_PID" &>/dev/null +then + echo "Atlantis failed to start" + cat /tmp/atlantis-server.log + exit 1 +fi +echo "Atlantis is running..." # start ngrok in the background and wait for it to start ./ngrok config add-authtoken $NGROK_AUTH_TOKEN > /dev/null 2>&1 ./ngrok http 4141 > /tmp/ngrok.log 2>&1 & +NGROK_PID=$! sleep 2 +if ! ps -p "$NGROK_PID" &>/dev/null +then + cleanup + echo "Ngrok failed to start" + cat /tmp/ngrok.log + exit 1 +fi +echo "Ngrok is running..." # find out what URL ngrok has given us export ATLANTIS_URL=$(curl -s 'http://localhost:4040/api/tunnels' | jq -r '.tunnels[] | select(.proto=="https") | .public_url') @@ -27,6 +74,7 @@ make build echo "Running e2e test: 'make run'" set +e +estatus=0 make run if [[ $? -eq 0 ]] then @@ -35,5 +83,7 @@ else echo "e2e tests failed" echo "atlantis logs:" cat /tmp/atlantis-server.log - exit 1 + estatus=1 fi +cleanup +exit $estatus diff --git a/server/controllers/api_controller.go b/server/controllers/api_controller.go index c48c99b41d..f9b6aa809b 100644 --- a/server/controllers/api_controller.go +++ b/server/controllers/api_controller.go @@ -78,7 +78,7 @@ func (a *APIController) apiReportError(w http.ResponseWriter, code int, err erro response, _ := json.Marshal(map[string]string{ "error": err.Error(), }) - a.respond(w, logging.Warn, code, string(response)) + a.respond(w, logging.Warn, code, "%s", string(response)) } func (a *APIController) Plan(w http.ResponseWriter, r *http.Request) { @@ -106,7 +106,7 @@ func (a *APIController) Plan(w http.ResponseWriter, r *http.Request) { a.apiReportError(w, http.StatusInternalServerError, err) return } - a.respond(w, logging.Debug, code, string(response)) + a.respond(w, logging.Warn, code, "%s", string(response)) } func (a *APIController) Apply(w http.ResponseWriter, r *http.Request) { @@ -141,7 +141,7 @@ func (a *APIController) Apply(w http.ResponseWriter, r *http.Request) { a.apiReportError(w, http.StatusInternalServerError, err) return } - a.respond(w, logging.Debug, code, string(response)) + a.respond(w, logging.Warn, code, "%s", string(response)) } func (a *APIController) apiPlan(request *APIRequest, ctx *command.Context) (*command.Result, error) { diff --git a/server/controllers/events/events_controller.go b/server/controllers/events/events_controller.go index a7ffa0c592..654b3eb5a0 100644 --- a/server/controllers/events/events_controller.go +++ b/server/controllers/events/events_controller.go @@ -174,7 +174,7 @@ func (e *VCSEventsController) handleGithubPost(w http.ResponseWriter, r *http.Re // Validate the request against the optional webhook secret. payload, err := e.GithubRequestValidator.Validate(r, e.GithubWebhookSecret) if err != nil { - e.respond(w, logging.Warn, http.StatusBadRequest, err.Error()) + e.respond(w, logging.Warn, http.StatusBadRequest, "%s", err.Error()) return } @@ -259,7 +259,7 @@ func (e *VCSEventsController) handleBitbucketServerPost(w http.ResponseWriter, r } if len(e.BitbucketWebhookSecret) > 0 { if err := bitbucketserver.ValidateSignature(body, sig, e.BitbucketWebhookSecret); err != nil { - e.respond(w, logging.Warn, http.StatusBadRequest, errors.Wrap(err, "request did not pass validation").Error()) + e.respond(w, logging.Warn, http.StatusBadRequest, "%s", errors.Wrap(err, "request did not pass validation").Error()) return } } @@ -281,7 +281,7 @@ func (e *VCSEventsController) handleAzureDevopsPost(w http.ResponseWriter, r *ht // Validate the request against the optional basic auth username and password. payload, err := e.AzureDevopsRequestValidator.Validate(r, e.AzureDevopsWebhookBasicUser, e.AzureDevopsWebhookBasicPassword) if err != nil { - e.respond(w, logging.Warn, http.StatusUnauthorized, err.Error()) + e.respond(w, logging.Warn, http.StatusUnauthorized, "%s", err.Error()) return } e.Logger.Debug("request valid") @@ -319,7 +319,7 @@ func (e *VCSEventsController) handleGiteaPost(w http.ResponseWriter, r *http.Req if len(e.GiteaWebhookSecret) > 0 { if err := gitea.ValidateSignature(body, signature, e.GiteaWebhookSecret); err != nil { - e.respond(w, logging.Warn, http.StatusBadRequest, errors.Wrap(err, "request did not pass validation").Error()) + e.respond(w, logging.Warn, http.StatusBadRequest, "%s", errors.Wrap(err, "request did not pass validation").Error()) return } } @@ -368,7 +368,7 @@ func (e *VCSEventsController) handleGiteaPullRequestEvent(w http.ResponseWriter, // Call a generic handler for pull request events response := e.handlePullRequestEvent(logger, baseRepo, headRepo, pull, user, pullEventType) - e.respond(w, logging.Debug, http.StatusOK, response.body) + e.respond(w, logging.Debug, http.StatusOK, "%s", response.body) } // HandleGiteaPullRequestCommentEvent handles comment events from Gitea where Atlantis commands can come from. @@ -386,7 +386,7 @@ func (e *VCSEventsController) HandleGiteaPullRequestCommentEvent(w http.Response // This follows the same approach as the GitHub client for handling comment events without full PR details response := e.handleCommentEvent(e.Logger, baseRepo, nil, nil, user, pullNum, event.Comment.Body, event.Comment.ID, models.Gitea) - e.respond(w, logging.Debug, http.StatusOK, response.body) + e.respond(w, logging.Debug, http.StatusOK, "%s", response.body) } // HandleGithubCommentEvent handles comment events from GitHub where Atlantis @@ -437,7 +437,7 @@ func (e *VCSEventsController) HandleBitbucketCloudCommentEvent(w http.ResponseWr code = resp.err.code msg = resp.err.err.Error() } - e.respond(w, lvl, code, msg) + e.respond(w, lvl, code, "%s", msg) } // HandleBitbucketServerCommentEvent handles comment events from Bitbucket. @@ -458,7 +458,7 @@ func (e *VCSEventsController) HandleBitbucketServerCommentEvent(w http.ResponseW code = resp.err.code msg = resp.err.err.Error() } - e.respond(w, lvl, code, msg) + e.respond(w, lvl, code, "%s", msg) } func (e *VCSEventsController) handleBitbucketCloudPullRequestEvent(w http.ResponseWriter, eventType string, body []byte, reqID string) { @@ -481,7 +481,7 @@ func (e *VCSEventsController) handleBitbucketCloudPullRequestEvent(w http.Respon code = resp.err.code msg = resp.err.err.Error() } - e.respond(w, lvl, code, msg) + e.respond(w, lvl, code, "%s", msg) } func (e *VCSEventsController) handleBitbucketServerPullRequestEvent(w http.ResponseWriter, eventType string, body []byte, reqID string) { @@ -503,7 +503,7 @@ func (e *VCSEventsController) handleBitbucketServerPullRequestEvent(w http.Respo code = resp.err.code msg = resp.err.err.Error() } - e.respond(w, lvl, code, msg) + e.respond(w, lvl, code, "%s", msg) } // HandleGithubPullRequestEvent will delete any locks associated with the pull @@ -592,7 +592,7 @@ func (e *VCSEventsController) handlePullRequestEvent(logger logging.SimpleLoggin func (e *VCSEventsController) handleGitlabPost(w http.ResponseWriter, r *http.Request) { event, err := e.GitlabRequestParserValidator.ParseAndValidate(r, e.GitlabWebhookSecret) if err != nil { - e.respond(w, logging.Warn, http.StatusBadRequest, err.Error()) + e.respond(w, logging.Warn, http.StatusBadRequest, "%s", err.Error()) return } e.Logger.Debug("request valid") @@ -633,7 +633,7 @@ func (e *VCSEventsController) HandleGitlabCommentEvent(w http.ResponseWriter, ev code = resp.err.code msg = resp.err.err.Error() } - e.respond(w, lvl, code, msg) + e.respond(w, lvl, code, "%s", msg) } func (e *VCSEventsController) handleCommentEvent(logger logging.SimpleLogging, baseRepo models.Repo, maybeHeadRepo *models.Repo, maybePull *models.PullRequest, user models.User, pullNum int, comment string, commentID int64, vcsHost models.VCSHostType) HTTPResponse { @@ -735,7 +735,7 @@ func (e *VCSEventsController) HandleGitlabMergeRequestEvent(w http.ResponseWrite code = resp.err.code msg = resp.err.err.Error() } - e.respond(w, lvl, code, msg) + e.respond(w, lvl, code, "%s", msg) } // HandleAzureDevopsPullRequestCommentedEvent handles comment events from Azure DevOps where Atlantis @@ -789,7 +789,7 @@ func (e *VCSEventsController) HandleAzureDevopsPullRequestCommentedEvent(w http. code = resp.err.code msg = resp.err.err.Error() } - e.respond(w, lvl, code, msg) + e.respond(w, lvl, code, "%s", msg) } // HandleAzureDevopsPullRequestEvent will delete any locks associated with the pull @@ -840,7 +840,7 @@ func (e *VCSEventsController) HandleAzureDevopsPullRequestEvent(w http.ResponseW code = resp.err.code msg = resp.err.err.Error() } - e.respond(w, lvl, code, msg) + e.respond(w, lvl, code, "%s", msg) } // supportsHost returns true if h is in e.SupportedVCSHosts and false otherwise. diff --git a/server/controllers/jobs_controller.go b/server/controllers/jobs_controller.go index bb38a05e44..2f27e32b97 100644 --- a/server/controllers/jobs_controller.go +++ b/server/controllers/jobs_controller.go @@ -41,7 +41,7 @@ func (j *JobsController) getProjectJobs(w http.ResponseWriter, r *http.Request) jobID, err := j.KeyGenerator.Generate(r) if err != nil { - j.respond(w, logging.Error, http.StatusBadRequest, err.Error()) + j.respond(w, logging.Error, http.StatusBadRequest, "%s", err.Error()) return err } @@ -67,7 +67,7 @@ func (j *JobsController) getProjectJobsWS(w http.ResponseWriter, r *http.Request err := j.WsMux.Handle(w, r) if err != nil { - j.respond(w, logging.Error, http.StatusInternalServerError, err.Error()) + j.respond(w, logging.Error, http.StatusInternalServerError, "%s", err.Error()) return err } diff --git a/server/events/markdown_renderer_test.go b/server/events/markdown_renderer_test.go index ace23c443a..39810dab13 100644 --- a/server/events/markdown_renderer_test.go +++ b/server/events/markdown_renderer_test.go @@ -475,6 +475,7 @@ $$$ </details> + #### Policy Approval Status: $$$ policy set: policy1: requires: 1 approval(s), have: 0. diff --git a/server/events/templates/policy_check_results_wrapped.tmpl b/server/events/templates/policy_check_results_wrapped.tmpl index 330980c2f4..49e38c46c4 100644 --- a/server/events/templates/policy_check_results_wrapped.tmpl +++ b/server/events/templates/policy_check_results_wrapped.tmpl @@ -2,9 +2,11 @@ <details><summary>Show Output</summary> {{- if eq .Command "Policy Check" }} {{- if ne .PreConftestOutput "" }} + ```diff {{ .PreConftestOutput }} ``` + {{- end -}} {{ template "policyCheck" .PolicySetResults }} {{- if ne .PostConftestOutput "" }} @@ -20,6 +22,7 @@ ``` {{- else }} </details> + #### Policy Approval Status: ``` {{ .PolicyApprovalSummary }} diff --git a/testdrive/utils.go b/testdrive/utils.go index 46d738a2d2..8e767a9518 100644 --- a/testdrive/utils.go +++ b/testdrive/utils.go @@ -35,7 +35,7 @@ import ( ) const hashicorpReleasesURL = "https://releases.hashicorp.com" -const terraformVersion = "1.9.3" // renovate: datasource=github-releases depName=hashicorp/terraform versioning=hashicorp +const terraformVersion = "1.9.5" // 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 a27de745f4..ded0d8928b 100644 --- a/testing/Dockerfile +++ b/testing/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22.5@sha256:86a3c48a61915a8c62c0e1d7594730399caa3feb73655dfe96c7bc17710e96cf +FROM golang:1.23.0@sha256:613a108a4a4b1dfb6923305db791a19d088f77632317cfc3446825c54fb862cd 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.9.3 +ENV TERRAFORM_VERSION=1.9.5 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} && \