diff --git a/runatlantis.io/docs/repo-level-atlantis-yaml.md b/runatlantis.io/docs/repo-level-atlantis-yaml.md
index 23afdac9ed..c596855bad 100644
--- a/runatlantis.io/docs/repo-level-atlantis-yaml.md
+++ b/runatlantis.io/docs/repo-level-atlantis-yaml.md
@@ -20,8 +20,8 @@ keys by setting the `allowed_overrides` key there. See the [Server Side Repo Con
more details.
**Notes**
-* `atlantis.yaml` files must be placed at the root of the repo
-* The only supported name is `atlantis.yaml`. Not `atlantis.yml` or `.atlantis.yaml`.
+* By default, repo root `atlantis.yaml` file is used.
+* You can change this behaviour by setting [Server Side Repo Config](server-side-repo-config.html)
::: danger DANGER
Atlantis uses the `atlantis.yaml` version from the pull request, similar to other
diff --git a/runatlantis.io/docs/server-side-repo-config.md b/runatlantis.io/docs/server-side-repo-config.md
index bc3ee64594..025df2c9ea 100644
--- a/runatlantis.io/docs/server-side-repo-config.md
+++ b/runatlantis.io/docs/server-side-repo-config.md
@@ -35,6 +35,10 @@ repos:
# By default, all branches are matched
branch: /.*/
+ # repo_config_file specifies which repo config file to use for this repo.
+ # By default, atlantis.yaml is used.
+ repo_config_file: path/to/atlantis.yaml
+
# apply_requirements sets the Apply Requirements for all repos that match.
apply_requirements: [approved, mergeable]
@@ -168,7 +172,7 @@ repos:
Then each allowed repo can have an `atlantis.yaml` file that
sets `apply_requirements` to an empty array (disabling the requirement).
```yaml
-# atlantis.yaml in the repo root
+# atlantis.yaml in the repo root or set repo_config_file in repos.yaml
version: 3
projects:
- dir: .
@@ -357,6 +361,54 @@ workflows:
See [Custom Workflows](custom-workflows.html) for more details on writing
custom workflows.
+### Multiple Atlantis Servers Handle The Same Repository
+Running multiple Atlantis servers to handle the same repository can be done to separate permissions for each Atlantis server.
+In this case, a different [atlantis.yaml](repo-level-atlantis-yaml.html) repository config file can be used by using different `repos.yaml` files.
+
+For example, consider a situation where a separate `production-server` atlantis uses repo config `atlantis-production.yaml` and `staging-server` atlantis uses repo config `atlantis-staging.yaml`.
+
+Firstly, deploy 2 Atlantis servers, `production-server` and `staging-server`.
+Each server has different permissions and a different `repos.yaml` file.
+The `repos.yaml` contains `repo_config_file` key to specify the repository atlantis config file path.
+
+```yaml
+# repos.yaml
+repos:
+- id: /.*/
+ # for production-server
+ repo_config_file: atlantis-production.yaml
+ # for staging-server
+ # repo_config_file: atlantis-staging.yaml
+```
+
+Then, create `atlantis-production.yaml` and `atlantis-staging.yaml` files in the repository.
+See the configuration examples in [atlantis.yaml](repo-level-atlantis-yaml.html).
+
+```yaml
+# atlantis-production.yaml
+version: 3
+projects:
+- name: project
+ branch: /production/
+ dir: infrastructure/production
+---
+# atlantis-staging.yaml
+version: 3
+projects:
+ - name: project
+ branch: /staging/
+ dir: infrastructure/staging
+```
+
+Now, 2 webhook URLs can be setup for the repository, which send events to `production-server` and `staging-server` respectively.
+Each servers handle different repository config files.
+
+:::tip Notes
+* If `no projects` comments are annoying, set [--silence-no-projects](server-configuration.html#silence-no-projects).
+* The command trigger executable name can be reconfigured from `atlantis` to something else by setting [Executable Name](server-configuration.html#executable-name).
+* When using different atlantis server vcs users such as `@atlantis-staging`, the comment `@atlantis-staging plan` can be used instead `atlantis plan` to call `staging-server` only.
+:::
+
## Reference
### Top-Level Keys
@@ -400,6 +452,7 @@ If you set a workflow with the key `default`, it will override this.
|-------------------------------|----------|---------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| id | string | none | yes | Value can be a regular expression when specified as /<regex>/ or an exact string match. Repo IDs are of the form `{vcs hostname}/{org}/{name}`, ex. `github.com/owner/repo`. Hostname is specified without scheme or port. For Bitbucket Server, {org} is the **name** of the project, not the key. |
| branch | string | none | no | An regex matching pull requests by base branch (the branch the pull request is getting merged into). By default, all branches are matched |
+| repo_config_file | string | none | no | Repo config file path in this repo. By default, use `atlantis.yaml` which is located on repository root. When multiple atlantis servers work with the same repo, please set different file names. |
| workflow | string | none | no | A custom workflow. |
| apply_requirements | []string | none | no | Requirements that must be satisfied before `atlantis apply` can be run. Currently the only supported requirements are `approved`, `mergeable`, and `undiverged`. See [Apply Requirements](apply-requirements.html) for more details. |
| allowed_overrides | []string | none | no | A list of restricted keys that `atlantis.yaml` files can override. The only supported keys are `apply_requirements`, `workflow`, `delete_source_branch_on_merge` and `repo_locking` |
diff --git a/server/controllers/events/events_controller_e2e_test.go b/server/controllers/events/events_controller_e2e_test.go
index e00afc6dfa..7fc1abe2ed 100644
--- a/server/controllers/events/events_controller_e2e_test.go
+++ b/server/controllers/events/events_controller_e2e_test.go
@@ -80,6 +80,8 @@ func TestGitHubWorkflow(t *testing.T) {
Description string
// RepoDir is relative to testfixtures/test-repos.
RepoDir string
+ // RepoConfigFile is path for atlantis.yaml
+ RepoConfigFile string
// ModifiedFiles are the list of files that have been modified in this
// pull request.
ModifiedFiles []string
@@ -218,6 +220,24 @@ func TestGitHubWorkflow(t *testing.T) {
{"exp-output-merge.txt"},
},
},
+ {
+ Description: "custom repo config file",
+ RepoDir: "repo-config-file",
+ RepoConfigFile: "infrastructure/custom-name-atlantis.yaml",
+ ModifiedFiles: []string{
+ "infrastructure/staging/main.tf",
+ "infrastructure/production/main.tf",
+ },
+ ExpAutoplan: true,
+ Comments: []string{
+ "atlantis apply",
+ },
+ ExpReplies: [][]string{
+ {"exp-output-autoplan.txt"},
+ {"exp-output-apply.txt"},
+ {"exp-output-merge.txt"},
+ },
+ },
{
Description: "modules staging only",
RepoDir: "modules",
@@ -393,7 +413,7 @@ func TestGitHubWorkflow(t *testing.T) {
userConfig = server.UserConfig{}
userConfig.DisableApply = c.DisableApply
- ctrl, vcsClient, githubGetter, atlantisWorkspace := setupE2E(t, c.RepoDir)
+ ctrl, vcsClient, githubGetter, atlantisWorkspace := setupE2E(t, c.RepoDir, c.RepoConfigFile)
// Set the repo to be cloned through the testing backdoor.
repoDir, headSHA := initializeRepo(t, c.RepoDir)
atlantisWorkspace.TestingOverrideHeadCloneURL = fmt.Sprintf("file://%s", repoDir)
@@ -542,7 +562,7 @@ func TestSimlpleWorkflow_terraformLockFile(t *testing.T) {
userConfig = server.UserConfig{}
userConfig.DisableApply = true
- ctrl, vcsClient, githubGetter, atlantisWorkspace := setupE2E(t, c.RepoDir)
+ ctrl, vcsClient, githubGetter, atlantisWorkspace := setupE2E(t, c.RepoDir, "")
// Set the repo to be cloned through the testing backdoor.
repoDir, headSHA := initializeRepo(t, c.RepoDir)
@@ -785,7 +805,7 @@ func TestGitHubWorkflowWithPolicyCheck(t *testing.T) {
userConfig.EnablePolicyChecksFlag = true
userConfig.QuietPolicyChecks = c.ExpQuietPolicyChecks
- ctrl, vcsClient, githubGetter, atlantisWorkspace := setupE2E(t, c.RepoDir)
+ ctrl, vcsClient, githubGetter, atlantisWorkspace := setupE2E(t, c.RepoDir, "")
// Set the repo to be cloned through the testing backdoor.
repoDir, headSHA := initializeRepo(t, c.RepoDir)
@@ -793,7 +813,7 @@ func TestGitHubWorkflowWithPolicyCheck(t *testing.T) {
// Setup test dependencies.
w := httptest.NewRecorder()
- When(vcsClient.PullIsMergeable(AnyRepo(), matchers.AnyModelsPullRequest(), "atlantis-test")).ThenReturn(true, nil)
+ When(vcsClient.PullIsMergeable(AnyRepo(), matchers.AnyModelsPullRequest(), EqString("atlantis-test"))).ThenReturn(true, nil)
When(vcsClient.PullIsApproved(AnyRepo(), matchers.AnyModelsPullRequest())).ThenReturn(models.ApprovalStatus{
IsApproved: true,
}, nil)
@@ -862,7 +882,7 @@ func TestGitHubWorkflowWithPolicyCheck(t *testing.T) {
}
}
-func setupE2E(t *testing.T, repoDir string) (events_controllers.VCSEventsController, *vcsmocks.MockClient, *mocks.MockGithubPullGetter, *events.FileWorkspace) {
+func setupE2E(t *testing.T, repoDir, repoConfigFile string) (events_controllers.VCSEventsController, *vcsmocks.MockClient, *mocks.MockGithubPullGetter, *events.FileWorkspace) {
allowForkPRs := false
dataDir, binDir, cacheDir := mkSubDirs(t)
@@ -917,9 +937,10 @@ func setupE2E(t *testing.T, repoDir string) (events_controllers.VCSEventsControl
parser := &config.ParserValidator{}
globalCfgArgs := valid.GlobalCfgArgs{
- AllowRepoCfg: true,
- MergeableReq: false,
- ApprovedReq: false,
+ RepoConfigFile: repoConfigFile,
+ AllowRepoCfg: true,
+ MergeableReq: false,
+ ApprovedReq: false,
PreWorkflowHooks: []*valid.WorkflowHook{
{
StepName: "global_hook",
diff --git a/server/controllers/events/testfixtures/test-repos/repo-config-file/exp-output-apply.txt b/server/controllers/events/testfixtures/test-repos/repo-config-file/exp-output-apply.txt
new file mode 100644
index 0000000000..50bd0ecd86
--- /dev/null
+++ b/server/controllers/events/testfixtures/test-repos/repo-config-file/exp-output-apply.txt
@@ -0,0 +1,28 @@
+Ran Apply for 2 projects:
+
+1. dir: `infrastructure/production` workspace: `default`
+1. dir: `infrastructure/staging` workspace: `default`
+
+### 1. dir: `infrastructure/production` workspace: `default`
+```diff
+null_resource.production[0]: Creating...
+null_resource.production[0]: Creation complete after *s [id=*******************]
+
+Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
+
+
+```
+
+---
+### 2. dir: `infrastructure/staging` workspace: `default`
+```diff
+null_resource.staging[0]: Creating...
+null_resource.staging[0]: Creation complete after *s [id=*******************]
+
+Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
+
+
+```
+
+---
+
diff --git a/server/controllers/events/testfixtures/test-repos/repo-config-file/exp-output-autoplan.txt b/server/controllers/events/testfixtures/test-repos/repo-config-file/exp-output-autoplan.txt
new file mode 100644
index 0000000000..064ce1766c
--- /dev/null
+++ b/server/controllers/events/testfixtures/test-repos/repo-config-file/exp-output-autoplan.txt
@@ -0,0 +1,69 @@
+Ran Plan for 2 projects:
+
+1. dir: `infrastructure/staging` workspace: `default`
+1. dir: `infrastructure/production` workspace: `default`
+
+### 1. dir: `infrastructure/staging` workspace: `default`
+Show Output
+
+```diff
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
++ create
+
+Terraform will perform the following actions:
+
+ # null_resource.staging[0] will be created
++ resource "null_resource" "staging" {
+ + id = (known after apply)
+ }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+
+```
+
+* :arrow_forward: To **apply** this plan, comment:
+ * `atlantis apply -d infrastructure/staging`
+* :put_litter_in_its_place: To **delete** this plan click [here](lock-url)
+* :repeat: To **plan** this project again, comment:
+ * `atlantis plan -d infrastructure/staging`
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+---
+### 2. dir: `infrastructure/production` workspace: `default`
+Show Output
+
+```diff
+
+Terraform used the selected providers to generate the following execution
+plan. Resource actions are indicated with the following symbols:
++ create
+
+Terraform will perform the following actions:
+
+ # null_resource.production[0] will be created
++ resource "null_resource" "production" {
+ + id = (known after apply)
+ }
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+
+```
+
+* :arrow_forward: To **apply** this plan, comment:
+ * `atlantis apply -d infrastructure/production`
+* :put_litter_in_its_place: To **delete** this plan click [here](lock-url)
+* :repeat: To **plan** this project again, comment:
+ * `atlantis plan -d infrastructure/production`
+
+Plan: 1 to add, 0 to change, 0 to destroy.
+
+---
+* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
+ * `atlantis apply`
+* :put_litter_in_its_place: To delete all plans and locks for the PR, comment:
+ * `atlantis unlock`
diff --git a/server/controllers/events/testfixtures/test-repos/repo-config-file/exp-output-merge.txt b/server/controllers/events/testfixtures/test-repos/repo-config-file/exp-output-merge.txt
new file mode 100644
index 0000000000..2c4580963f
--- /dev/null
+++ b/server/controllers/events/testfixtures/test-repos/repo-config-file/exp-output-merge.txt
@@ -0,0 +1,4 @@
+Locks and plans deleted for the projects and workspaces modified in this pull request:
+
+- dir: `infrastructure/production` workspace: `default`
+- dir: `infrastructure/staging` workspace: `default`
\ No newline at end of file
diff --git a/server/controllers/events/testfixtures/test-repos/repo-config-file/infrastructure/custom-name-atlantis.yaml b/server/controllers/events/testfixtures/test-repos/repo-config-file/infrastructure/custom-name-atlantis.yaml
new file mode 100644
index 0000000000..6d1626307e
--- /dev/null
+++ b/server/controllers/events/testfixtures/test-repos/repo-config-file/infrastructure/custom-name-atlantis.yaml
@@ -0,0 +1,4 @@
+version: 3
+projects:
+- dir: infrastructure/staging
+- dir: infrastructure/production
diff --git a/server/controllers/events/testfixtures/test-repos/repo-config-file/infrastructure/production/main.tf b/server/controllers/events/testfixtures/test-repos/repo-config-file/infrastructure/production/main.tf
new file mode 100644
index 0000000000..ef2b2c2903
--- /dev/null
+++ b/server/controllers/events/testfixtures/test-repos/repo-config-file/infrastructure/production/main.tf
@@ -0,0 +1,3 @@
+resource "null_resource" "production" {
+ count = "1"
+}
diff --git a/server/controllers/events/testfixtures/test-repos/repo-config-file/infrastructure/staging/main.tf b/server/controllers/events/testfixtures/test-repos/repo-config-file/infrastructure/staging/main.tf
new file mode 100644
index 0000000000..a7920c24c7
--- /dev/null
+++ b/server/controllers/events/testfixtures/test-repos/repo-config-file/infrastructure/staging/main.tf
@@ -0,0 +1,3 @@
+resource "null_resource" "staging" {
+ count = "1"
+}
diff --git a/server/core/config/parser_validator.go b/server/core/config/parser_validator.go
index 4e23c1d4f8..96f707e6bf 100644
--- a/server/core/config/parser_validator.go
+++ b/server/core/config/parser_validator.go
@@ -15,9 +15,6 @@ import (
yaml "gopkg.in/yaml.v2"
)
-// AtlantisYAMLFilename is the name of the config file for each repo.
-const AtlantisYAMLFilename = "atlantis.yaml"
-
// ParserValidator parses and validates server-side repo config files and
// repo-level atlantis.yaml files.
type ParserValidator struct{}
@@ -25,15 +22,15 @@ type ParserValidator struct{}
// HasRepoCfg returns true if there is a repo config (atlantis.yaml) file
// for the repo at absRepoDir.
// Returns an error if for some reason it can't read that directory.
-func (p *ParserValidator) HasRepoCfg(absRepoDir string) (bool, error) {
+func (p *ParserValidator) HasRepoCfg(absRepoDir, repoConfigFile string) (bool, error) {
// Checks for a config file with an invalid extension (atlantis.yml)
const invalidExtensionFilename = "atlantis.yml"
_, err := os.Stat(p.repoCfgPath(absRepoDir, invalidExtensionFilename))
if err == nil {
- return false, errors.Errorf("found %q as config file; rename using the .yaml extension - %q", invalidExtensionFilename, AtlantisYAMLFilename)
+ return false, errors.Errorf("found %q as config file; rename using the .yaml extension", invalidExtensionFilename)
}
- _, err = os.Stat(p.repoCfgPath(absRepoDir, AtlantisYAMLFilename))
+ _, err = os.Stat(p.repoCfgPath(absRepoDir, repoConfigFile))
if os.IsNotExist(err) {
return false, nil
}
@@ -44,12 +41,13 @@ func (p *ParserValidator) HasRepoCfg(absRepoDir string) (bool, error) {
// repo at absRepoDir.
// If there was no config file, it will return an os.IsNotExist(error).
func (p *ParserValidator) ParseRepoCfg(absRepoDir string, globalCfg valid.GlobalCfg, repoID string, branch string) (valid.RepoCfg, error) {
- configFile := p.repoCfgPath(absRepoDir, AtlantisYAMLFilename)
+ repoConfigFile := globalCfg.RepoConfigFile(repoID)
+ configFile := p.repoCfgPath(absRepoDir, repoConfigFile)
configData, err := os.ReadFile(configFile) // nolint: gosec
if err != nil {
if !os.IsNotExist(err) {
- return valid.RepoCfg{}, errors.Wrapf(err, "unable to read %s file", AtlantisYAMLFilename)
+ return valid.RepoCfg{}, errors.Wrapf(err, "unable to read %s file", repoConfigFile)
}
// Don't wrap os.IsNotExist errors because we want our callers to be
// able to detect if it's a NotExist err.
diff --git a/server/core/config/parser_validator_test.go b/server/core/config/parser_validator_test.go
index 08e07987fc..c3eb9b28e9 100644
--- a/server/core/config/parser_validator_test.go
+++ b/server/core/config/parser_validator_test.go
@@ -25,7 +25,7 @@ var globalCfg = valid.NewGlobalCfgFromArgs(globalCfgArgs)
func TestHasRepoCfg_DirDoesNotExist(t *testing.T) {
r := config.ParserValidator{}
- exists, err := r.HasRepoCfg("/not/exist")
+ exists, err := r.HasRepoCfg("/not/exist", "unused.yaml")
Ok(t, err)
Equals(t, false, exists)
}
@@ -33,19 +33,20 @@ func TestHasRepoCfg_DirDoesNotExist(t *testing.T) {
func TestHasRepoCfg_FileDoesNotExist(t *testing.T) {
tmpDir := t.TempDir()
r := config.ParserValidator{}
- exists, err := r.HasRepoCfg(tmpDir)
+ exists, err := r.HasRepoCfg(tmpDir, "not-exist.yaml")
Ok(t, err)
Equals(t, false, exists)
}
func TestHasRepoCfg_InvalidFileExtension(t *testing.T) {
tmpDir := t.TempDir()
- _, err := os.Create(filepath.Join(tmpDir, "atlantis.yml"))
+ repoConfigFile := "atlantis.yml"
+ _, err := os.Create(filepath.Join(tmpDir, repoConfigFile))
Ok(t, err)
r := config.ParserValidator{}
- _, err = r.HasRepoCfg(tmpDir)
- ErrContains(t, "found \"atlantis.yml\" as config file; rename using the .yaml extension - \"atlantis.yaml\"", err)
+ _, err = r.HasRepoCfg(tmpDir, repoConfigFile)
+ ErrContains(t, "found \"atlantis.yml\" as config file; rename using the .yaml extension", err)
}
func TestParseRepoCfg_DirDoesNotExist(t *testing.T) {
@@ -1212,6 +1213,18 @@ func TestParseGlobalCfg(t *testing.T) {
branch: /?/`,
expErr: "repos: (0: (branch: parsing: /?/: error parsing regexp: missing argument to repetition operator: `?`.).).",
},
+ "invalid repo_config_file which starts with a slash": {
+ input: `repos:
+- id: /.*/
+ repo_config_file: /etc/passwd`,
+ expErr: "repos: (0: (repo_config_file: must not starts with a slash '/'.).).",
+ },
+ "invalid repo_config_file which contains parent directory path": {
+ input: `repos:
+- id: /.*/
+ repo_config_file: ../../etc/passwd`,
+ expErr: "repos: (0: (repo_config_file: must not contains parent directory path like '../'.).).",
+ },
"workflow doesn't exist": {
input: `repos:
- id: /.*/
@@ -1300,7 +1313,7 @@ workflows:
input: `
repos:
- id: github.com/owner/repo
-
+ repo_config_file: "path/to/atlantis.yaml"
apply_requirements: [approved, mergeable]
pre_workflow_hooks:
- run: custom workflow command
@@ -1345,6 +1358,7 @@ policies:
defaultCfg.Repos[0],
{
ID: "github.com/owner/repo",
+ RepoConfigFile: "path/to/atlantis.yaml",
ApplyRequirements: []string{"approved", "mergeable"},
PreWorkflowHooks: preWorkflowHooks,
Workflow: &customWorkflow1,
diff --git a/server/core/config/raw/global_cfg.go b/server/core/config/raw/global_cfg.go
index b998342133..a6c4b90f60 100644
--- a/server/core/config/raw/global_cfg.go
+++ b/server/core/config/raw/global_cfg.go
@@ -22,6 +22,7 @@ type GlobalCfg struct {
type Repo struct {
ID string `yaml:"id" json:"id"`
Branch string `yaml:"branch" json:"branch"`
+ RepoConfigFile string `yaml:"repo_config_file" json:"repo_config_file"`
ApplyRequirements []string `yaml:"apply_requirements" json:"apply_requirements"`
PreWorkflowHooks []WorkflowHook `yaml:"pre_workflow_hooks" json:"pre_workflow_hooks"`
Workflow *string `yaml:"workflow,omitempty" json:"workflow,omitempty"`
@@ -171,6 +172,20 @@ func (r Repo) Validate() error {
return errors.Wrapf(err, "parsing: %s", branch)
}
+ repoConfigFileValid := func(value interface{}) error {
+ repoConfigFile := value.(string)
+ if repoConfigFile == "" {
+ return nil
+ }
+ if strings.HasPrefix(repoConfigFile, "/") {
+ return errors.New("must not starts with a slash '/'")
+ }
+ if strings.Contains(repoConfigFile, "../") || strings.Contains(repoConfigFile, "..\\") {
+ return errors.New("must not contains parent directory path like '../'")
+ }
+ return nil
+ }
+
overridesValid := func(value interface{}) error {
overrides := value.([]string)
for _, o := range overrides {
@@ -195,6 +210,7 @@ func (r Repo) Validate() error {
return validation.ValidateStruct(&r,
validation.Field(&r.ID, validation.Required, validation.By(idValid)),
validation.Field(&r.Branch, validation.By(branchValid)),
+ validation.Field(&r.RepoConfigFile, validation.By(repoConfigFileValid)),
validation.Field(&r.AllowedOverrides, validation.By(overridesValid)),
validation.Field(&r.ApplyRequirements, validation.By(validApplyReq)),
validation.Field(&r.Workflow, validation.By(workflowExists)),
@@ -261,6 +277,7 @@ OUTER:
ID: id,
IDRegex: idRegex,
BranchRegex: branchRegex,
+ RepoConfigFile: r.RepoConfigFile,
ApplyRequirements: mergedApplyReqs,
PreWorkflowHooks: preWorkflowHooks,
Workflow: workflow,
diff --git a/server/core/config/valid/global_cfg.go b/server/core/config/valid/global_cfg.go
index ecf4ec5cf8..ebdd7546dc 100644
--- a/server/core/config/valid/global_cfg.go
+++ b/server/core/config/valid/global_cfg.go
@@ -24,6 +24,9 @@ const DefaultWorkflowName = "default"
const DeleteSourceBranchOnMergeKey = "delete_source_branch_on_merge"
const RepoLockingKey = "repo_locking"
+// DefaultAtlantisFile is the default name of the config file for each repo.
+const DefaultAtlantisFile = "atlantis.yaml"
+
// NonOverrideableApplyReqs will get applied across all "repos" in the server side config.
// If repo config is allowed overrides, they can override this.
// TODO: Make this more customizable, not everyone wants this rigid workflow
@@ -62,6 +65,7 @@ type Repo struct {
// If ID is set then this will be nil.
IDRegex *regexp.Regexp
BranchRegex *regexp.Regexp
+ RepoConfigFile string
ApplyRequirements []string
PreWorkflowHooks []*WorkflowHook
Workflow *Workflow
@@ -157,6 +161,7 @@ func NewGlobalCfg(allowRepoCfg bool, mergeableReq bool, approvedReq bool) Global
}
type GlobalCfgArgs struct {
+ RepoConfigFile string
AllowRepoCfg bool
MergeableReq bool
ApprovedReq bool
@@ -205,6 +210,7 @@ func NewGlobalCfgFromArgs(args GlobalCfgArgs) GlobalCfg {
{
IDRegex: regexp.MustCompile(".*"),
BranchRegex: regexp.MustCompile(".*"),
+ RepoConfigFile: args.RepoConfigFile,
ApplyRequirements: applyReqs,
PreWorkflowHooks: args.PreWorkflowHooks,
Workflow: &defaultWorkflow,
@@ -521,3 +527,13 @@ func (g GlobalCfg) MatchingRepo(repoID string) *Repo {
}
return nil
}
+
+// RepoConfigFile returns a repository specific file path
+// If not defined, return atlantis.yaml as default
+func (g GlobalCfg) RepoConfigFile(repoID string) string {
+ repo := g.MatchingRepo(repoID)
+ if repo != nil && repo.RepoConfigFile != "" {
+ return repo.RepoConfigFile
+ }
+ return DefaultAtlantisFile
+}
diff --git a/server/events/command/project_context.go b/server/events/command/project_context.go
index 4a772b7158..139731d96d 100644
--- a/server/events/command/project_context.go
+++ b/server/events/command/project_context.go
@@ -90,6 +90,8 @@ type ProjectContext struct {
DeleteSourceBranchOnMerge bool
// RepoLocking will get a lock when plan
RepoLocking bool
+ // RepoConfigFile
+ RepoConfigFile string
// UUID for atlantis logs
JobID string
// The index of order group. Before planning/applying it will use to sort projects. Default is 0.
diff --git a/server/events/comment_parser.go b/server/events/comment_parser.go
index 0c8928a35b..3dcdcc6f9f 100644
--- a/server/events/comment_parser.go
+++ b/server/events/comment_parser.go
@@ -24,7 +24,6 @@ import (
"text/template"
"github.com/flynn-archive/go-shlex"
- "github.com/runatlantis/atlantis/server/core/config"
"github.com/runatlantis/atlantis/server/events/command"
"github.com/runatlantis/atlantis/server/events/models"
"github.com/spf13/pflag"
@@ -191,7 +190,7 @@ func (e *CommentParser) Parse(rawComment string, vcsHost models.VCSHostType) Com
flagSet.SetOutput(io.Discard)
flagSet.StringVarP(&workspace, workspaceFlagLong, workspaceFlagShort, "", "Switch to this Terraform workspace before planning.")
flagSet.StringVarP(&dir, dirFlagLong, dirFlagShort, "", "Which directory to run plan in relative to root of repo, ex. 'child/dir'.")
- flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", fmt.Sprintf("Which project to run plan for. Refers to the name of the project configured in %s. Cannot be used at same time as workspace or dir flags.", config.AtlantisYAMLFilename))
+ flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", "Which project to run plan for. Refers to the name of the project configured in a repo config file. Cannot be used at same time as workspace or dir flags.")
flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.")
case command.Apply.String():
name = command.Apply
@@ -199,7 +198,7 @@ func (e *CommentParser) Parse(rawComment string, vcsHost models.VCSHostType) Com
flagSet.SetOutput(io.Discard)
flagSet.StringVarP(&workspace, workspaceFlagLong, workspaceFlagShort, "", "Apply the plan for this Terraform workspace.")
flagSet.StringVarP(&dir, dirFlagLong, dirFlagShort, "", "Apply the plan for this directory, relative to root of repo, ex. 'child/dir'.")
- flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", fmt.Sprintf("Apply the plan for this project. Refers to the name of the project configured in %s. Cannot be used at same time as workspace or dir flags.", config.AtlantisYAMLFilename))
+ flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", "Apply the plan for this project. Refers to the name of the project configured in a repo config file. Cannot be used at same time as workspace or dir flags.")
flagSet.BoolVarP(&autoMergeDisabled, autoMergeDisabledFlagLong, autoMergeDisabledFlagShort, false, "Disable automerge after apply.")
flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.")
case command.ApprovePolicies.String():
@@ -216,7 +215,7 @@ func (e *CommentParser) Parse(rawComment string, vcsHost models.VCSHostType) Com
flagSet = pflag.NewFlagSet(command.Version.String(), pflag.ContinueOnError)
flagSet.StringVarP(&workspace, workspaceFlagLong, workspaceFlagShort, "", "Switch to this Terraform workspace before running version.")
flagSet.StringVarP(&dir, dirFlagLong, dirFlagShort, "", "Which directory to run version in relative to root of repo, ex. 'child/dir'.")
- flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", fmt.Sprintf("Print the version for this project. Refers to the name of the project configured in %s.", config.AtlantisYAMLFilename))
+ flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", "Print the version for this project. Refers to the name of the project configured in a repo config file.")
flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.")
default:
return CommentParseResult{CommentResponse: fmt.Sprintf("Error: unknown command %q – this is a bug", cmd)}
diff --git a/server/events/comment_parser_test.go b/server/events/comment_parser_test.go
index aec505a1da..22d8ea3e38 100644
--- a/server/events/comment_parser_test.go
+++ b/server/events/comment_parser_test.go
@@ -854,8 +854,8 @@ var PlanUsage = `Usage of plan:
-d, --dir string Which directory to run plan in relative to root of repo,
ex. 'child/dir'.
-p, --project string Which project to run plan for. Refers to the name of the
- project configured in atlantis.yaml. Cannot be used at
- same time as workspace or dir flags.
+ project configured in a repo config file. Cannot be used
+ at same time as workspace or dir flags.
--verbose Append Atlantis log to comment.
-w, --workspace string Switch to this Terraform workspace before planning.
`
@@ -865,8 +865,8 @@ var ApplyUsage = `Usage of apply:
-d, --dir string Apply the plan for this directory, relative to root of
repo, ex. 'child/dir'.
-p, --project string Apply the plan for this project. Refers to the name of
- the project configured in atlantis.yaml. Cannot be
- used at same time as workspace or dir flags.
+ the project configured in a repo config file. Cannot
+ be used at same time as workspace or dir flags.
--verbose Append Atlantis log to comment.
-w, --workspace string Apply the plan for this Terraform workspace.
`
diff --git a/server/events/project_command_builder.go b/server/events/project_command_builder.go
index 7eabadcb7c..6d58a79b96 100644
--- a/server/events/project_command_builder.go
+++ b/server/events/project_command_builder.go
@@ -241,17 +241,18 @@ func (p *DefaultProjectCommandBuilder) buildPlanAllCommands(ctx *command.Context
ctx.Log.Debug("%d files were modified in this pull request", len(modifiedFiles))
if p.SkipCloneNoChanges && p.VCSClient.SupportsSingleFileDownload(ctx.Pull.BaseRepo) {
- hasRepoCfg, repoCfgData, err := p.VCSClient.DownloadRepoConfigFile(ctx.Pull)
+ repoCfgFile := p.GlobalCfg.RepoConfigFile(ctx.Pull.BaseRepo.ID())
+ hasRepoCfg, repoCfgData, err := p.VCSClient.GetFileContent(ctx.Pull, repoCfgFile)
if err != nil {
- return nil, errors.Wrapf(err, "downloading %s", config.AtlantisYAMLFilename)
+ return nil, errors.Wrapf(err, "downloading %s", repoCfgFile)
}
if hasRepoCfg {
repoCfg, err := p.ParserValidator.ParseRepoCfgData(repoCfgData, p.GlobalCfg, ctx.Pull.BaseRepo.ID(), ctx.Pull.BaseBranch)
if err != nil {
- return nil, errors.Wrapf(err, "parsing %s", config.AtlantisYAMLFilename)
+ return nil, errors.Wrapf(err, "parsing %s", repoCfgFile)
}
- ctx.Log.Info("successfully parsed remote %s file", config.AtlantisYAMLFilename)
+ ctx.Log.Info("successfully parsed remote %s file", repoCfgFile)
if len(repoCfg.Projects) > 0 {
matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, "")
if err != nil {
@@ -263,7 +264,7 @@ func (p *DefaultProjectCommandBuilder) buildPlanAllCommands(ctx *command.Context
return []command.ProjectContext{}, nil
}
} else {
- ctx.Log.Info("No projects are defined in %s. Will resume automatic detection", config.AtlantisYAMLFilename)
+ ctx.Log.Info("No projects are defined in %s. Will resume automatic detection", repoCfgFile)
}
// NOTE: We discard this work here and end up doing it again after
// cloning to ensure all the return values are set properly with
@@ -288,9 +289,10 @@ func (p *DefaultProjectCommandBuilder) buildPlanAllCommands(ctx *command.Context
}
// Parse config file if it exists.
- hasRepoCfg, err := p.ParserValidator.HasRepoCfg(repoDir)
+ repoCfgFile := p.GlobalCfg.RepoConfigFile(ctx.Pull.BaseRepo.ID())
+ hasRepoCfg, err := p.ParserValidator.HasRepoCfg(repoDir, repoCfgFile)
if err != nil {
- return nil, errors.Wrapf(err, "looking for %s file in %q", config.AtlantisYAMLFilename, repoDir)
+ return nil, errors.Wrapf(err, "looking for %s file in %q", repoCfgFile, repoDir)
}
var projCtxs []command.ProjectContext
@@ -301,9 +303,9 @@ func (p *DefaultProjectCommandBuilder) buildPlanAllCommands(ctx *command.Context
// should be planed.
repoCfg, err = p.ParserValidator.ParseRepoCfg(repoDir, p.GlobalCfg, ctx.Pull.BaseRepo.ID(), ctx.Pull.BaseBranch)
if err != nil {
- return nil, errors.Wrapf(err, "parsing %s", config.AtlantisYAMLFilename)
+ return nil, errors.Wrapf(err, "parsing %s", repoCfgFile)
}
- ctx.Log.Info("successfully parsed %s file", config.AtlantisYAMLFilename)
+ ctx.Log.Info("successfully parsed %s file", repoCfgFile)
}
if len(repoCfg.Projects) > 0 {
@@ -334,9 +336,9 @@ func (p *DefaultProjectCommandBuilder) buildPlanAllCommands(ctx *command.Context
// If there is no config file or it specified no projects, then we'll plan each project that
// our algorithm determines was modified.
if hasRepoCfg {
- ctx.Log.Info("No projects are defined in %s. Will resume automatic detection", config.AtlantisYAMLFilename)
+ ctx.Log.Info("No projects are defined in %s. Will resume automatic detection", repoCfgFile)
} else {
- ctx.Log.Info("found no %s file", config.AtlantisYAMLFilename)
+ ctx.Log.Info("found no %s file", repoCfgFile)
}
// build a module index for projects that are explicitly included
moduleInfo, err := FindModuleProjects(repoDir, p.AutoDetectModuleFiles)
@@ -476,14 +478,15 @@ func (p *DefaultProjectCommandBuilder) buildProjectPlanCommand(ctx *command.Cont
// getCfg returns the atlantis.yaml config (if it exists) for this project. If
// there is no config, then projectCfg and repoCfg will be nil.
func (p *DefaultProjectCommandBuilder) getCfg(ctx *command.Context, projectName string, dir string, workspace string, repoDir string) (projectsCfg []valid.Project, repoCfg *valid.RepoCfg, err error) {
- hasConfigFile, err := p.ParserValidator.HasRepoCfg(repoDir)
+ repoCfgFile := p.GlobalCfg.RepoConfigFile(ctx.Pull.BaseRepo.ID())
+ hasRepoCfg, err := p.ParserValidator.HasRepoCfg(repoDir, repoCfgFile)
if err != nil {
- err = errors.Wrapf(err, "looking for %s file in %q", config.AtlantisYAMLFilename, repoDir)
+ err = errors.Wrapf(err, "looking for %s file in %q", repoCfgFile, repoDir)
return
}
- if !hasConfigFile {
+ if !hasRepoCfg {
if projectName != "" {
- err = fmt.Errorf("cannot specify a project name unless an %s file exists to configure projects", config.AtlantisYAMLFilename)
+ err = fmt.Errorf("cannot specify a project name unless an %s file exists to configure projects", repoCfgFile)
return
}
return
@@ -507,7 +510,7 @@ func (p *DefaultProjectCommandBuilder) getCfg(ctx *command.Context, projectName
}
}
if len(projectsCfg) == 0 {
- err = fmt.Errorf("no project with name %q is defined in %s", projectName, config.AtlantisYAMLFilename)
+ err = fmt.Errorf("no project with name %q is defined in %s", projectName, repoCfgFile)
return
}
return
@@ -518,7 +521,7 @@ func (p *DefaultProjectCommandBuilder) getCfg(ctx *command.Context, projectName
return
}
if len(projCfgs) > 1 {
- err = fmt.Errorf("must specify project name: more than one project defined in %s matched dir: %q workspace: %q", config.AtlantisYAMLFilename, dir, workspace)
+ err = fmt.Errorf("must specify project name: more than one project defined in %s matched dir: %q workspace: %q", repoCfgFile, dir, workspace)
return
}
projectsCfg = projCfgs
diff --git a/server/events/project_command_builder_test.go b/server/events/project_command_builder_test.go
index 2e9438fabd..9c3f8b8349 100644
--- a/server/events/project_command_builder_test.go
+++ b/server/events/project_command_builder_test.go
@@ -135,7 +135,7 @@ projects:
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn([]string{"main.tf"}, nil)
if c.AtlantisYAML != "" {
- err := os.WriteFile(filepath.Join(tmpDir, config.AtlantisYAMLFilename), []byte(c.AtlantisYAML), 0600)
+ err := os.WriteFile(filepath.Join(tmpDir, valid.DefaultAtlantisFile), []byte(c.AtlantisYAML), 0600)
Ok(t, err)
}
@@ -404,7 +404,7 @@ projects:
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn([]string{"main.tf"}, nil)
if c.AtlantisYAML != "" {
- err := os.WriteFile(filepath.Join(tmpDir, config.AtlantisYAMLFilename), []byte(c.AtlantisYAML), 0600)
+ err := os.WriteFile(filepath.Join(tmpDir, valid.DefaultAtlantisFile), []byte(c.AtlantisYAML), 0600)
Ok(t, err)
}
@@ -577,7 +577,7 @@ projects:
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn(c.ModifiedFiles, nil)
if c.AtlantisYAML != "" {
- err := os.WriteFile(filepath.Join(tmpDir, config.AtlantisYAMLFilename), []byte(c.AtlantisYAML), 0600)
+ err := os.WriteFile(filepath.Join(tmpDir, valid.DefaultAtlantisFile), []byte(c.AtlantisYAML), 0600)
Ok(t, err)
}
@@ -747,7 +747,7 @@ projects:
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn(c.ModifiedFiles, nil)
if c.AtlantisYAML != "" {
- err := os.WriteFile(filepath.Join(tmpDir, config.AtlantisYAMLFilename), []byte(c.AtlantisYAML), 0600)
+ err := os.WriteFile(filepath.Join(tmpDir, valid.DefaultAtlantisFile), []byte(c.AtlantisYAML), 0600)
Ok(t, err)
}
@@ -914,7 +914,7 @@ projects:
- dir: .
workspace: staging
`
- err := os.WriteFile(filepath.Join(repoDir, config.AtlantisYAMLFilename), []byte(yamlCfg), 0600)
+ err := os.WriteFile(filepath.Join(repoDir, valid.DefaultAtlantisFile), []byte(yamlCfg), 0600)
Ok(t, err)
When(workingDir.Clone(
@@ -1141,7 +1141,7 @@ projects:
"project1": map[string]interface{}{
"main.tf": fmt.Sprintf(baseVersionConfig, exactSymbols[0]),
},
- config.AtlantisYAMLFilename: atlantisYamlContent,
+ valid.DefaultAtlantisFile: atlantisYamlContent,
},
ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"},
Exp: map[string][]int{
@@ -1154,7 +1154,7 @@ projects:
"project1": map[string]interface{}{
"main.tf": nil,
},
- config.AtlantisYAMLFilename: atlantisYamlContent,
+ valid.DefaultAtlantisFile: atlantisYamlContent,
},
ModifiedFiles: []string{"project1/main.tf"},
Exp: map[string][]int{
@@ -1298,7 +1298,7 @@ parallel_plan: true`,
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn(c.ModifiedFiles, nil)
When(vcsClient.SupportsSingleFileDownload(matchers.AnyModelsRepo())).ThenReturn(true)
- When(vcsClient.DownloadRepoConfigFile(matchers.AnyModelsPullRequest())).ThenReturn(true, []byte(c.AtlantisYAML), nil)
+ When(vcsClient.GetFileContent(matchers.AnyModelsPullRequest(), AnyString())).ThenReturn(true, []byte(c.AtlantisYAML), nil)
workingDir := mocks.NewMockWorkingDir()
logger := logging.NewNoopLogger(t)
diff --git a/server/events/vcs/azuredevops_client.go b/server/events/vcs/azuredevops_client.go
index 72aaf0ccdb..9c0e6d2971 100644
--- a/server/events/vcs/azuredevops_client.go
+++ b/server/events/vcs/azuredevops_client.go
@@ -389,7 +389,7 @@ func (g *AzureDevopsClient) SupportsSingleFileDownload(repo models.Repo) bool {
return false
}
-func (g *AzureDevopsClient) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) {
+func (g *AzureDevopsClient) GetFileContent(pull models.PullRequest, fileName string) (bool, []byte, error) {
return false, []byte{}, fmt.Errorf("Not Implemented")
}
diff --git a/server/events/vcs/bitbucketcloud/client.go b/server/events/vcs/bitbucketcloud/client.go
index 4bdad53128..d8d964f892 100644
--- a/server/events/vcs/bitbucketcloud/client.go
+++ b/server/events/vcs/bitbucketcloud/client.go
@@ -260,10 +260,10 @@ func (b *Client) SupportsSingleFileDownload(models.Repo) bool {
return false
}
-// DownloadRepoConfigFile return `atlantis.yaml` content from VCS (which support fetch a single file from repository)
-// The first return value indicate that repo contain atlantis.yaml or not
-// if BaseRepo had one repo config file, its content will placed on the second return value
-func (b *Client) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) {
+// GetFileContent a repository file content from VCS (which support fetch a single file from repository)
+// The first return value indicates whether the repo contains a file or not
+// if BaseRepo had a file, its content will placed on the second return value
+func (b *Client) GetFileContent(pull models.PullRequest, fileName string) (bool, []byte, error) {
return false, []byte{}, fmt.Errorf("Not Implemented")
}
diff --git a/server/events/vcs/bitbucketserver/client.go b/server/events/vcs/bitbucketserver/client.go
index 88ba703272..8c78f2df5c 100644
--- a/server/events/vcs/bitbucketserver/client.go
+++ b/server/events/vcs/bitbucketserver/client.go
@@ -346,10 +346,10 @@ func (b *Client) SupportsSingleFileDownload(repo models.Repo) bool {
return false
}
-// DownloadRepoConfigFile return `atlantis.yaml` content from VCS (which support fetch a single file from repository)
-// The first return value indicate that repo contain atlantis.yaml or not
-// if BaseRepo had one repo config file, its content will placed on the second return value
-func (b *Client) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) {
+// GetFileContent a repository file content from VCS (which support fetch a single file from repository)
+// The first return value indicates whether the repo contains a file or not
+// if BaseRepo had a file, its content will placed on the second return value
+func (b *Client) GetFileContent(pull models.PullRequest, fileName string) (bool, []byte, error) {
return false, []byte{}, fmt.Errorf("not implemented")
}
diff --git a/server/events/vcs/client.go b/server/events/vcs/client.go
index 170ea1ad59..c11b30725c 100644
--- a/server/events/vcs/client.go
+++ b/server/events/vcs/client.go
@@ -40,10 +40,10 @@ type Client interface {
MarkdownPullLink(pull models.PullRequest) (string, error)
GetTeamNamesForUser(repo models.Repo, user models.User) ([]string, error)
- // DownloadRepoConfigFile return `atlantis.yaml` content from VCS (which support fetch a single file from repository)
- // The first return value indicate that repo contain atlantis.yaml or not
- // if BaseRepo had one repo config file, its content will placed on the second return value
- DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error)
+ // GetFileContent a repository file content from VCS (which support fetch a single file from repository)
+ // The first return value indicates whether the repo contains a file or not
+ // if BaseRepo had a file, its content will placed on the second return value
+ GetFileContent(pull models.PullRequest, fileName string) (bool, []byte, error)
SupportsSingleFileDownload(repo models.Repo) bool
GetCloneURL(VCSHostType models.VCSHostType, repo string) (string, error)
}
diff --git a/server/events/vcs/github_client.go b/server/events/vcs/github_client.go
index 1517dc9239..1e5c70f0da 100644
--- a/server/events/vcs/github_client.go
+++ b/server/events/vcs/github_client.go
@@ -23,7 +23,6 @@ import (
"github.com/google/go-github/v31/github"
"github.com/pkg/errors"
- "github.com/runatlantis/atlantis/server/core/config"
"github.com/runatlantis/atlantis/server/events/command"
"github.com/runatlantis/atlantis/server/events/models"
"github.com/runatlantis/atlantis/server/events/vcs/common"
@@ -577,12 +576,12 @@ func (g *GithubClient) ExchangeCode(code string) (*GithubAppTemporarySecrets, er
return data, err
}
-// DownloadRepoConfigFile return `atlantis.yaml` content from VCS (which support fetch a single file from repository)
-// The first return value indicate that repo contain atlantis.yaml or not
-// if BaseRepo had one repo config file, its content will placed on the second return value
-func (g *GithubClient) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) {
+// GetFileContent a repository file content from VCS (which support fetch a single file from repository)
+// The first return value indicates whether the repo contains a file or not
+// if BaseRepo had a file, its content will placed on the second return value
+func (g *GithubClient) GetFileContent(pull models.PullRequest, fileName string) (bool, []byte, error) {
opt := github.RepositoryContentGetOptions{Ref: pull.HeadBranch}
- fileContent, _, resp, err := g.client.Repositories.GetContents(g.ctx, pull.BaseRepo.Owner, pull.BaseRepo.Name, config.AtlantisYAMLFilename, &opt)
+ fileContent, _, resp, err := g.client.Repositories.GetContents(g.ctx, pull.BaseRepo.Owner, pull.BaseRepo.Name, fileName, &opt)
if resp.StatusCode == http.StatusNotFound {
return false, []byte{}, nil
diff --git a/server/events/vcs/gitlab_client.go b/server/events/vcs/gitlab_client.go
index b829401550..ac54ce6ffd 100644
--- a/server/events/vcs/gitlab_client.go
+++ b/server/events/vcs/gitlab_client.go
@@ -22,8 +22,6 @@ import (
"strings"
"time"
- "github.com/runatlantis/atlantis/server/core/config"
-
"github.com/runatlantis/atlantis/server/events/command"
"github.com/runatlantis/atlantis/server/events/vcs/common"
@@ -377,13 +375,13 @@ func (g *GitlabClient) GetTeamNamesForUser(repo models.Repo, user models.User) (
return nil, nil
}
-// DownloadRepoConfigFile return `atlantis.yaml` content from VCS (which support fetch a single file from repository)
-// The first return value indicate that repo contain atlantis.yaml or not
-// if BaseRepo had one repo config file, its content will placed on the second return value
-func (g *GitlabClient) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) {
+// GetFileContent a repository file content from VCS (which support fetch a single file from repository)
+// The first return value indicates whether the repo contains a file or not
+// if BaseRepo had a file, its content will placed on the second return value
+func (g *GitlabClient) GetFileContent(pull models.PullRequest, fileName string) (bool, []byte, error) {
opt := gitlab.GetRawFileOptions{Ref: gitlab.String(pull.HeadBranch)}
- bytes, resp, err := g.Client.RepositoryFiles.GetRawFile(pull.BaseRepo.FullName, config.AtlantisYAMLFilename, &opt)
+ bytes, resp, err := g.Client.RepositoryFiles.GetRawFile(pull.BaseRepo.FullName, fileName, &opt)
if resp.StatusCode == http.StatusNotFound {
return false, []byte{}, nil
}
diff --git a/server/events/vcs/mocks/matchers/models_user.go b/server/events/vcs/mocks/matchers/models_user.go
new file mode 100644
index 0000000000..0aa92b5d88
--- /dev/null
+++ b/server/events/vcs/mocks/matchers/models_user.go
@@ -0,0 +1,33 @@
+// Code generated by pegomock. DO NOT EDIT.
+package matchers
+
+import (
+ "github.com/petergtz/pegomock"
+ "reflect"
+
+ models "github.com/runatlantis/atlantis/server/events/models"
+)
+
+func AnyModelsUser() models.User {
+ pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.User))(nil)).Elem()))
+ var nullValue models.User
+ return nullValue
+}
+
+func EqModelsUser(value models.User) models.User {
+ pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value})
+ var nullValue models.User
+ return nullValue
+}
+
+func NotEqModelsUser(value models.User) models.User {
+ pegomock.RegisterMatcher(&pegomock.NotEqMatcher{Value: value})
+ var nullValue models.User
+ return nullValue
+}
+
+func ModelsUserThat(matcher pegomock.ArgumentMatcher) models.User {
+ pegomock.RegisterMatcher(matcher)
+ var nullValue models.User
+ return nullValue
+}
diff --git a/server/events/vcs/mocks/matchers/models_vcshosttype.go b/server/events/vcs/mocks/matchers/models_vcshosttype.go
new file mode 100644
index 0000000000..a54447f7de
--- /dev/null
+++ b/server/events/vcs/mocks/matchers/models_vcshosttype.go
@@ -0,0 +1,33 @@
+// Code generated by pegomock. DO NOT EDIT.
+package matchers
+
+import (
+ "github.com/petergtz/pegomock"
+ "reflect"
+
+ models "github.com/runatlantis/atlantis/server/events/models"
+)
+
+func AnyModelsVCSHostType() models.VCSHostType {
+ pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.VCSHostType))(nil)).Elem()))
+ var nullValue models.VCSHostType
+ return nullValue
+}
+
+func EqModelsVCSHostType(value models.VCSHostType) models.VCSHostType {
+ pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value})
+ var nullValue models.VCSHostType
+ return nullValue
+}
+
+func NotEqModelsVCSHostType(value models.VCSHostType) models.VCSHostType {
+ pegomock.RegisterMatcher(&pegomock.NotEqMatcher{Value: value})
+ var nullValue models.VCSHostType
+ return nullValue
+}
+
+func ModelsVCSHostTypeThat(matcher pegomock.ArgumentMatcher) models.VCSHostType {
+ pegomock.RegisterMatcher(matcher)
+ var nullValue models.VCSHostType
+ return nullValue
+}
diff --git a/server/events/vcs/mocks/mock_client.go b/server/events/vcs/mocks/mock_client.go
index 3522cc8e0f..dcdba57901 100644
--- a/server/events/vcs/mocks/mock_client.go
+++ b/server/events/vcs/mocks/mock_client.go
@@ -4,11 +4,10 @@
package mocks
import (
- "reflect"
- "time"
-
pegomock "github.com/petergtz/pegomock"
models "github.com/runatlantis/atlantis/server/events/models"
+ "reflect"
+ "time"
)
type MockClient struct {
@@ -26,11 +25,30 @@ func NewMockClient(options ...pegomock.Option) *MockClient {
func (mock *MockClient) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh }
func (mock *MockClient) FailHandler() pegomock.FailHandler { return mock.fail }
-func (mock *MockClient) CreateComment(_param0 models.Repo, _param1 int, _param2 string, _param3 string) error {
+func (mock *MockClient) GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error) {
+ if mock == nil {
+ panic("mock must not be nil. Use myMock := NewMockClient().")
+ }
+ params := []pegomock.Param{repo, pull}
+ result := pegomock.GetGenericMockFrom(mock).Invoke("GetModifiedFiles", 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 *MockClient) CreateComment(repo models.Repo, pullNum int, comment string, command string) error {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClient().")
}
- params := []pegomock.Param{_param0, _param1, _param2, _param3}
+ params := []pegomock.Param{repo, pullNum, comment, command}
result := pegomock.GetGenericMockFrom(mock).Invoke("CreateComment", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
var ret0 error
if len(result) != 0 {
@@ -41,40 +59,32 @@ func (mock *MockClient) CreateComment(_param0 models.Repo, _param1 int, _param2
return ret0
}
-func (mock *MockClient) DownloadRepoConfigFile(_param0 models.PullRequest) (bool, []byte, error) {
+func (mock *MockClient) HidePrevCommandComments(repo models.Repo, pullNum int, command string) error {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClient().")
}
- params := []pegomock.Param{_param0}
- result := pegomock.GetGenericMockFrom(mock).Invoke("DownloadRepoConfigFile", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*[]byte)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
- var ret0 bool
- var ret1 []byte
- var ret2 error
+ params := []pegomock.Param{repo, pullNum, command}
+ result := pegomock.GetGenericMockFrom(mock).Invoke("HidePrevCommandComments", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
+ var ret0 error
if len(result) != 0 {
if result[0] != nil {
- ret0 = result[0].(bool)
- }
- if result[1] != nil {
- ret1 = result[1].([]byte)
- }
- if result[2] != nil {
- ret2 = result[2].(error)
+ ret0 = result[0].(error)
}
}
- return ret0, ret1, ret2
+ return ret0
}
-func (mock *MockClient) GetModifiedFiles(_param0 models.Repo, _param1 models.PullRequest) ([]string, error) {
+func (mock *MockClient) PullIsApproved(repo models.Repo, pull models.PullRequest) (models.ApprovalStatus, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClient().")
}
- params := []pegomock.Param{_param0, _param1}
- result := pegomock.GetGenericMockFrom(mock).Invoke("GetModifiedFiles", params, []reflect.Type{reflect.TypeOf((*[]string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
- var ret0 []string
+ params := []pegomock.Param{repo, pull}
+ result := pegomock.GetGenericMockFrom(mock).Invoke("PullIsApproved", params, []reflect.Type{reflect.TypeOf((*models.ApprovalStatus)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
+ var ret0 models.ApprovalStatus
var ret1 error
if len(result) != 0 {
if result[0] != nil {
- ret0 = result[0].([]string)
+ ret0 = result[0].(models.ApprovalStatus)
}
if result[1] != nil {
ret1 = result[1].(error)
@@ -83,45 +93,45 @@ func (mock *MockClient) GetModifiedFiles(_param0 models.Repo, _param1 models.Pul
return ret0, ret1
}
-func (mock *MockClient) HidePrevCommandComments(_param0 models.Repo, _param1 int, _param2 string) error {
+func (mock *MockClient) PullIsMergeable(repo models.Repo, pull models.PullRequest, vcsstatusname string) (bool, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClient().")
}
- params := []pegomock.Param{_param0, _param1, _param2}
- result := pegomock.GetGenericMockFrom(mock).Invoke("HidePrevCommandComments", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
- var ret0 error
+ params := []pegomock.Param{repo, pull, vcsstatusname}
+ result := pegomock.GetGenericMockFrom(mock).Invoke("PullIsMergeable", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
+ var ret0 bool
+ var ret1 error
if len(result) != 0 {
if result[0] != nil {
- ret0 = result[0].(error)
+ ret0 = result[0].(bool)
+ }
+ if result[1] != nil {
+ ret1 = result[1].(error)
}
}
- return ret0
+ return ret0, ret1
}
-func (mock *MockClient) MarkdownPullLink(_param0 models.PullRequest) (string, error) {
+func (mock *MockClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClient().")
}
- params := []pegomock.Param{_param0}
- result := pegomock.GetGenericMockFrom(mock).Invoke("MarkdownPullLink", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
- var ret0 string
- var ret1 error
+ params := []pegomock.Param{repo, pull, state, src, description, url}
+ result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateStatus", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
+ var ret0 error
if len(result) != 0 {
if result[0] != nil {
- ret0 = result[0].(string)
- }
- if result[1] != nil {
- ret1 = result[1].(error)
+ ret0 = result[0].(error)
}
}
- return ret0, ret1
+ return ret0
}
-func (mock *MockClient) MergePull(_param0 models.PullRequest, _param1 models.PullRequestOptions) error {
+func (mock *MockClient) MergePull(pull models.PullRequest, pullOptions models.PullRequestOptions) error {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClient().")
}
- params := []pegomock.Param{_param0, _param1}
+ params := []pegomock.Param{pull, pullOptions}
result := pegomock.GetGenericMockFrom(mock).Invoke("MergePull", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
var ret0 error
if len(result) != 0 {
@@ -132,17 +142,17 @@ func (mock *MockClient) MergePull(_param0 models.PullRequest, _param1 models.Pul
return ret0
}
-func (mock *MockClient) PullIsApproved(_param0 models.Repo, _param1 models.PullRequest) (models.ApprovalStatus, error) {
+func (mock *MockClient) MarkdownPullLink(pull models.PullRequest) (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClient().")
}
- params := []pegomock.Param{_param0, _param1}
- result := pegomock.GetGenericMockFrom(mock).Invoke("PullIsApproved", params, []reflect.Type{reflect.TypeOf((*models.ApprovalStatus)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
- var ret0 models.ApprovalStatus
+ params := []pegomock.Param{pull}
+ result := pegomock.GetGenericMockFrom(mock).Invoke("MarkdownPullLink", 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].(models.ApprovalStatus)
+ ret0 = result[0].(string)
}
if result[1] != nil {
ret1 = result[1].(error)
@@ -170,30 +180,34 @@ func (mock *MockClient) GetTeamNamesForUser(repo models.Repo, user models.User)
return ret0, ret1
}
-func (mock *MockClient) PullIsMergeable(_param0 models.Repo, _param1 models.PullRequest, vcsstatusname string) (bool, error) {
+func (mock *MockClient) GetFileContent(pull models.PullRequest, fileName string) (bool, []byte, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClient().")
}
- params := []pegomock.Param{_param0, _param1}
- result := pegomock.GetGenericMockFrom(mock).Invoke("PullIsMergeable", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
+ params := []pegomock.Param{pull, fileName}
+ result := pegomock.GetGenericMockFrom(mock).Invoke("GetFileContent", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*[]byte)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 bool
- var ret1 error
+ var ret1 []byte
+ var ret2 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(bool)
}
if result[1] != nil {
- ret1 = result[1].(error)
+ ret1 = result[1].([]byte)
+ }
+ if result[2] != nil {
+ ret2 = result[2].(error)
}
}
- return ret0, ret1
+ return ret0, ret1, ret2
}
-func (mock *MockClient) SupportsSingleFileDownload(_param0 models.Repo) bool {
+func (mock *MockClient) SupportsSingleFileDownload(repo models.Repo) bool {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClient().")
}
- params := []pegomock.Param{_param0}
+ params := []pegomock.Param{repo}
result := pegomock.GetGenericMockFrom(mock).Invoke("SupportsSingleFileDownload", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()})
var ret0 bool
if len(result) != 0 {
@@ -204,11 +218,11 @@ func (mock *MockClient) SupportsSingleFileDownload(_param0 models.Repo) bool {
return ret0
}
-func (mock *MockClient) GetCloneURL(_param0 models.VCSHostType, _param1 string) (string, error) {
+func (mock *MockClient) GetCloneURL(VCSHostType models.VCSHostType, repo string) (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClient().")
}
- params := []pegomock.Param{_param0, _param1}
+ params := []pegomock.Param{VCSHostType, repo}
result := pegomock.GetGenericMockFrom(mock).Invoke("GetCloneURL", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 string
var ret1 error
@@ -223,21 +237,6 @@ func (mock *MockClient) GetCloneURL(_param0 models.VCSHostType, _param1 string)
return ret0, ret1
}
-func (mock *MockClient) UpdateStatus(_param0 models.Repo, _param1 models.PullRequest, _param2 models.CommitStatus, _param3 string, _param4 string, _param5 string) error {
- if mock == nil {
- panic("mock must not be nil. Use myMock := NewMockClient().")
- }
- params := []pegomock.Param{_param0, _param1, _param2, _param3, _param4, _param5}
- result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateStatus", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
- var ret0 error
- if len(result) != 0 {
- if result[0] != nil {
- ret0 = result[0].(error)
- }
- }
- return ret0
-}
-
func (mock *MockClient) VerifyWasCalledOnce() *VerifierMockClient {
return &VerifierMockClient{
mock: mock,
@@ -275,8 +274,39 @@ type VerifierMockClient struct {
timeout time.Duration
}
-func (verifier *VerifierMockClient) CreateComment(_param0 models.Repo, _param1 int, _param2 string, _param3 string) *MockClient_CreateComment_OngoingVerification {
- params := []pegomock.Param{_param0, _param1, _param2, _param3}
+func (verifier *VerifierMockClient) GetModifiedFiles(repo models.Repo, pull models.PullRequest) *MockClient_GetModifiedFiles_OngoingVerification {
+ params := []pegomock.Param{repo, pull}
+ methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetModifiedFiles", params, verifier.timeout)
+ return &MockClient_GetModifiedFiles_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
+}
+
+type MockClient_GetModifiedFiles_OngoingVerification struct {
+ mock *MockClient
+ methodInvocations []pegomock.MethodInvocation
+}
+
+func (c *MockClient_GetModifiedFiles_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest) {
+ repo, pull := c.GetAllCapturedArguments()
+ return repo[len(repo)-1], pull[len(pull)-1]
+}
+
+func (c *MockClient_GetModifiedFiles_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) {
+ 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)
+ }
+ }
+ return
+}
+
+func (verifier *VerifierMockClient) CreateComment(repo models.Repo, pullNum int, comment string, command string) *MockClient_CreateComment_OngoingVerification {
+ params := []pegomock.Param{repo, pullNum, comment, command}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CreateComment", params, verifier.timeout)
return &MockClient_CreateComment_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
@@ -287,8 +317,8 @@ type MockClient_CreateComment_OngoingVerification struct {
}
func (c *MockClient_CreateComment_OngoingVerification) GetCapturedArguments() (models.Repo, int, string, string) {
- _param0, _param1, _param2, _param3 := c.GetAllCapturedArguments()
- return _param0[len(_param0)-1], _param1[len(_param1)-1], _param2[len(_param2)-1], _param3[len(_param3)-1]
+ repo, pullNum, comment, command := c.GetAllCapturedArguments()
+ return repo[len(repo)-1], pullNum[len(pullNum)-1], comment[len(comment)-1], command[len(command)-1]
}
func (c *MockClient_CreateComment_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []int, _param2 []string, _param3 []string) {
@@ -314,50 +344,58 @@ func (c *MockClient_CreateComment_OngoingVerification) GetAllCapturedArguments()
return
}
-func (verifier *VerifierMockClient) DownloadRepoConfigFile(_param0 models.PullRequest) *MockClient_DownloadRepoConfigFile_OngoingVerification {
- params := []pegomock.Param{_param0}
- methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DownloadRepoConfigFile", params, verifier.timeout)
- return &MockClient_DownloadRepoConfigFile_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
+func (verifier *VerifierMockClient) HidePrevCommandComments(repo models.Repo, pullNum int, command string) *MockClient_HidePrevCommandComments_OngoingVerification {
+ params := []pegomock.Param{repo, pullNum, command}
+ methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "HidePrevCommandComments", params, verifier.timeout)
+ return &MockClient_HidePrevCommandComments_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
-type MockClient_DownloadRepoConfigFile_OngoingVerification struct {
+type MockClient_HidePrevCommandComments_OngoingVerification struct {
mock *MockClient
methodInvocations []pegomock.MethodInvocation
}
-func (c *MockClient_DownloadRepoConfigFile_OngoingVerification) GetCapturedArguments() models.PullRequest {
- _param0 := c.GetAllCapturedArguments()
- return _param0[len(_param0)-1]
+func (c *MockClient_HidePrevCommandComments_OngoingVerification) GetCapturedArguments() (models.Repo, int, string) {
+ repo, pullNum, command := c.GetAllCapturedArguments()
+ return repo[len(repo)-1], pullNum[len(pullNum)-1], command[len(command)-1]
}
-func (c *MockClient_DownloadRepoConfigFile_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest) {
+func (c *MockClient_HidePrevCommandComments_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []int, _param2 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
- _param0 = make([]models.PullRequest, len(c.methodInvocations))
+ _param0 = make([]models.Repo, len(c.methodInvocations))
for u, param := range params[0] {
- _param0[u] = param.(models.PullRequest)
+ _param0[u] = param.(models.Repo)
+ }
+ _param1 = make([]int, len(c.methodInvocations))
+ for u, param := range params[1] {
+ _param1[u] = param.(int)
+ }
+ _param2 = make([]string, len(c.methodInvocations))
+ for u, param := range params[2] {
+ _param2[u] = param.(string)
}
}
return
}
-func (verifier *VerifierMockClient) GetModifiedFiles(_param0 models.Repo, _param1 models.PullRequest) *MockClient_GetModifiedFiles_OngoingVerification {
- params := []pegomock.Param{_param0, _param1}
- methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetModifiedFiles", params, verifier.timeout)
- return &MockClient_GetModifiedFiles_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
+func (verifier *VerifierMockClient) PullIsApproved(repo models.Repo, pull models.PullRequest) *MockClient_PullIsApproved_OngoingVerification {
+ params := []pegomock.Param{repo, pull}
+ methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PullIsApproved", params, verifier.timeout)
+ return &MockClient_PullIsApproved_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
-type MockClient_GetModifiedFiles_OngoingVerification struct {
+type MockClient_PullIsApproved_OngoingVerification struct {
mock *MockClient
methodInvocations []pegomock.MethodInvocation
}
-func (c *MockClient_GetModifiedFiles_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest) {
- _param0, _param1 := c.GetAllCapturedArguments()
- return _param0[len(_param0)-1], _param1[len(_param1)-1]
+func (c *MockClient_PullIsApproved_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest) {
+ repo, pull := c.GetAllCapturedArguments()
+ return repo[len(repo)-1], pull[len(pull)-1]
}
-func (c *MockClient_GetModifiedFiles_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) {
+func (c *MockClient_PullIsApproved_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]models.Repo, len(c.methodInvocations))
@@ -372,32 +410,32 @@ func (c *MockClient_GetModifiedFiles_OngoingVerification) GetAllCapturedArgument
return
}
-func (verifier *VerifierMockClient) HidePrevCommandComments(_param0 models.Repo, _param1 int, _param2 string) *MockClient_HidePrevCommandComments_OngoingVerification {
- params := []pegomock.Param{_param0, _param1, _param2}
- methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "HidePrevCommandComments", params, verifier.timeout)
- return &MockClient_HidePrevCommandComments_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
+func (verifier *VerifierMockClient) PullIsMergeable(repo models.Repo, pull models.PullRequest, vcsstatusname string) *MockClient_PullIsMergeable_OngoingVerification {
+ params := []pegomock.Param{repo, pull, vcsstatusname}
+ methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PullIsMergeable", params, verifier.timeout)
+ return &MockClient_PullIsMergeable_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
-type MockClient_HidePrevCommandComments_OngoingVerification struct {
+type MockClient_PullIsMergeable_OngoingVerification struct {
mock *MockClient
methodInvocations []pegomock.MethodInvocation
}
-func (c *MockClient_HidePrevCommandComments_OngoingVerification) GetCapturedArguments() (models.Repo, int, string) {
- _param0, _param1, _param2 := c.GetAllCapturedArguments()
- return _param0[len(_param0)-1], _param1[len(_param1)-1], _param2[len(_param2)-1]
+func (c *MockClient_PullIsMergeable_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, string) {
+ repo, pull, vcsstatusname := c.GetAllCapturedArguments()
+ return repo[len(repo)-1], pull[len(pull)-1], vcsstatusname[len(vcsstatusname)-1]
}
-func (c *MockClient_HidePrevCommandComments_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []int, _param2 []string) {
+func (c *MockClient_PullIsMergeable_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([]int, len(c.methodInvocations))
+ _param1 = make([]models.PullRequest, len(c.methodInvocations))
for u, param := range params[1] {
- _param1[u] = param.(int)
+ _param1[u] = param.(models.PullRequest)
}
_param2 = make([]string, len(c.methodInvocations))
for u, param := range params[2] {
@@ -407,35 +445,55 @@ func (c *MockClient_HidePrevCommandComments_OngoingVerification) GetAllCapturedA
return
}
-func (verifier *VerifierMockClient) MarkdownPullLink(_param0 models.PullRequest) *MockClient_MarkdownPullLink_OngoingVerification {
- params := []pegomock.Param{_param0}
- methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "MarkdownPullLink", params, verifier.timeout)
- return &MockClient_MarkdownPullLink_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
+func (verifier *VerifierMockClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) *MockClient_UpdateStatus_OngoingVerification {
+ params := []pegomock.Param{repo, pull, state, src, description, url}
+ methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateStatus", params, verifier.timeout)
+ return &MockClient_UpdateStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
-type MockClient_MarkdownPullLink_OngoingVerification struct {
+type MockClient_UpdateStatus_OngoingVerification struct {
mock *MockClient
methodInvocations []pegomock.MethodInvocation
}
-func (c *MockClient_MarkdownPullLink_OngoingVerification) GetCapturedArguments() models.PullRequest {
- _param0 := c.GetAllCapturedArguments()
- return _param0[len(_param0)-1]
+func (c *MockClient_UpdateStatus_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, models.CommitStatus, string, string, string) {
+ repo, pull, state, src, description, url := c.GetAllCapturedArguments()
+ return repo[len(repo)-1], pull[len(pull)-1], state[len(state)-1], src[len(src)-1], description[len(description)-1], url[len(url)-1]
}
-func (c *MockClient_MarkdownPullLink_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest) {
+func (c *MockClient_UpdateStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []models.CommitStatus, _param3 []string, _param4 []string, _param5 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
- _param0 = make([]models.PullRequest, len(c.methodInvocations))
+ _param0 = make([]models.Repo, len(c.methodInvocations))
for u, param := range params[0] {
- _param0[u] = param.(models.PullRequest)
+ _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([]models.CommitStatus, len(c.methodInvocations))
+ for u, param := range params[2] {
+ _param2[u] = param.(models.CommitStatus)
+ }
+ _param3 = make([]string, len(c.methodInvocations))
+ for u, param := range params[3] {
+ _param3[u] = param.(string)
+ }
+ _param4 = make([]string, len(c.methodInvocations))
+ for u, param := range params[4] {
+ _param4[u] = param.(string)
+ }
+ _param5 = make([]string, len(c.methodInvocations))
+ for u, param := range params[5] {
+ _param5[u] = param.(string)
}
}
return
}
-func (verifier *VerifierMockClient) MergePull(_param0 models.PullRequest, _param1 models.PullRequestOptions) *MockClient_MergePull_OngoingVerification {
- params := []pegomock.Param{_param0, _param1}
+func (verifier *VerifierMockClient) MergePull(pull models.PullRequest, pullOptions models.PullRequestOptions) *MockClient_MergePull_OngoingVerification {
+ params := []pegomock.Param{pull, pullOptions}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "MergePull", params, verifier.timeout)
return &MockClient_MergePull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
@@ -446,8 +504,8 @@ type MockClient_MergePull_OngoingVerification struct {
}
func (c *MockClient_MergePull_OngoingVerification) GetCapturedArguments() (models.PullRequest, models.PullRequestOptions) {
- _param0, _param1 := c.GetAllCapturedArguments()
- return _param0[len(_param0)-1], _param1[len(_param1)-1]
+ pull, pullOptions := c.GetAllCapturedArguments()
+ return pull[len(pull)-1], pullOptions[len(pullOptions)-1]
}
func (c *MockClient_MergePull_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest, _param1 []models.PullRequestOptions) {
@@ -465,43 +523,33 @@ func (c *MockClient_MergePull_OngoingVerification) GetAllCapturedArguments() (_p
return
}
-func (verifier *VerifierMockClient) PullIsApproved(_param0 models.Repo, _param1 models.PullRequest) *MockClient_PullIsApproved_OngoingVerification {
- params := []pegomock.Param{_param0, _param1}
- methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PullIsApproved", params, verifier.timeout)
- return &MockClient_PullIsApproved_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
+func (verifier *VerifierMockClient) MarkdownPullLink(pull models.PullRequest) *MockClient_MarkdownPullLink_OngoingVerification {
+ params := []pegomock.Param{pull}
+ methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "MarkdownPullLink", params, verifier.timeout)
+ return &MockClient_MarkdownPullLink_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
-type MockClient_PullIsApproved_OngoingVerification struct {
+type MockClient_MarkdownPullLink_OngoingVerification struct {
mock *MockClient
methodInvocations []pegomock.MethodInvocation
}
-func (c *MockClient_PullIsApproved_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest) {
- _param0, _param1 := c.GetAllCapturedArguments()
- return _param0[len(_param0)-1], _param1[len(_param1)-1]
+func (c *MockClient_MarkdownPullLink_OngoingVerification) GetCapturedArguments() models.PullRequest {
+ pull := c.GetAllCapturedArguments()
+ return pull[len(pull)-1]
}
-func (c *MockClient_PullIsApproved_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) {
+func (c *MockClient_MarkdownPullLink_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
- _param0 = make([]models.Repo, len(c.methodInvocations))
+ _param0 = make([]models.PullRequest, 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)
+ _param0[u] = param.(models.PullRequest)
}
}
return
}
-func (verifier *VerifierMockClient) PullIsMergeable(_param0 models.Repo, _param1 models.PullRequest) *MockClient_PullIsMergeable_OngoingVerification {
- params := []pegomock.Param{_param0, _param1}
- methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PullIsMergeable", params, verifier.timeout)
- return &MockClient_PullIsMergeable_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
-}
-
func (verifier *VerifierMockClient) GetTeamNamesForUser(repo models.Repo, user models.User) *MockClient_GetTeamNamesForUser_OngoingVerification {
params := []pegomock.Param{repo, user}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetTeamNamesForUser", params, verifier.timeout)
@@ -513,33 +561,59 @@ type MockClient_GetTeamNamesForUser_OngoingVerification struct {
methodInvocations []pegomock.MethodInvocation
}
-type MockClient_PullIsMergeable_OngoingVerification struct {
+func (c *MockClient_GetTeamNamesForUser_OngoingVerification) GetCapturedArguments() (models.Repo, models.User) {
+ repo, user := c.GetAllCapturedArguments()
+ return repo[len(repo)-1], user[len(user)-1]
+}
+
+func (c *MockClient_GetTeamNamesForUser_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.User) {
+ 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.User, len(c.methodInvocations))
+ for u, param := range params[1] {
+ _param1[u] = param.(models.User)
+ }
+ }
+ return
+}
+
+func (verifier *VerifierMockClient) GetFileContent(pull models.PullRequest, fileName string) *MockClient_GetFileContent_OngoingVerification {
+ params := []pegomock.Param{pull, fileName}
+ methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetFileContent", params, verifier.timeout)
+ return &MockClient_GetFileContent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
+}
+
+type MockClient_GetFileContent_OngoingVerification struct {
mock *MockClient
methodInvocations []pegomock.MethodInvocation
}
-func (c *MockClient_PullIsMergeable_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest) {
- _param0, _param1 := c.GetAllCapturedArguments()
- return _param0[len(_param0)-1], _param1[len(_param1)-1]
+func (c *MockClient_GetFileContent_OngoingVerification) GetCapturedArguments() (models.PullRequest, string) {
+ pull, fileName := c.GetAllCapturedArguments()
+ return pull[len(pull)-1], fileName[len(fileName)-1]
}
-func (c *MockClient_PullIsMergeable_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) {
+func (c *MockClient_GetFileContent_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest, _param1 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
- _param0 = make([]models.Repo, len(c.methodInvocations))
+ _param0 = make([]models.PullRequest, len(c.methodInvocations))
for u, param := range params[0] {
- _param0[u] = param.(models.Repo)
+ _param0[u] = param.(models.PullRequest)
}
- _param1 = make([]models.PullRequest, len(c.methodInvocations))
+ _param1 = make([]string, len(c.methodInvocations))
for u, param := range params[1] {
- _param1[u] = param.(models.PullRequest)
+ _param1[u] = param.(string)
}
}
return
}
-func (verifier *VerifierMockClient) SupportsSingleFileDownload(_param0 models.Repo) *MockClient_SupportsSingleFileDownload_OngoingVerification {
- params := []pegomock.Param{_param0}
+func (verifier *VerifierMockClient) SupportsSingleFileDownload(repo models.Repo) *MockClient_SupportsSingleFileDownload_OngoingVerification {
+ params := []pegomock.Param{repo}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "SupportsSingleFileDownload", params, verifier.timeout)
return &MockClient_SupportsSingleFileDownload_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
@@ -550,8 +624,8 @@ type MockClient_SupportsSingleFileDownload_OngoingVerification struct {
}
func (c *MockClient_SupportsSingleFileDownload_OngoingVerification) GetCapturedArguments() models.Repo {
- _param0 := c.GetAllCapturedArguments()
- return _param0[len(_param0)-1]
+ repo := c.GetAllCapturedArguments()
+ return repo[len(repo)-1]
}
func (c *MockClient_SupportsSingleFileDownload_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo) {
@@ -565,48 +639,32 @@ func (c *MockClient_SupportsSingleFileDownload_OngoingVerification) GetAllCaptur
return
}
-func (verifier *VerifierMockClient) UpdateStatus(_param0 models.Repo, _param1 models.PullRequest, _param2 models.CommitStatus, _param3 string, _param4 string, _param5 string) *MockClient_UpdateStatus_OngoingVerification {
- params := []pegomock.Param{_param0, _param1, _param2, _param3, _param4, _param5}
- methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateStatus", params, verifier.timeout)
- return &MockClient_UpdateStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
+func (verifier *VerifierMockClient) GetCloneURL(VCSHostType models.VCSHostType, repo string) *MockClient_GetCloneURL_OngoingVerification {
+ params := []pegomock.Param{VCSHostType, repo}
+ methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetCloneURL", params, verifier.timeout)
+ return &MockClient_GetCloneURL_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
-type MockClient_UpdateStatus_OngoingVerification struct {
+type MockClient_GetCloneURL_OngoingVerification struct {
mock *MockClient
methodInvocations []pegomock.MethodInvocation
}
-func (c *MockClient_UpdateStatus_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, models.CommitStatus, string, string, string) {
- _param0, _param1, _param2, _param3, _param4, _param5 := c.GetAllCapturedArguments()
- return _param0[len(_param0)-1], _param1[len(_param1)-1], _param2[len(_param2)-1], _param3[len(_param3)-1], _param4[len(_param4)-1], _param5[len(_param5)-1]
+func (c *MockClient_GetCloneURL_OngoingVerification) GetCapturedArguments() (models.VCSHostType, string) {
+ VCSHostType, repo := c.GetAllCapturedArguments()
+ return VCSHostType[len(VCSHostType)-1], repo[len(repo)-1]
}
-func (c *MockClient_UpdateStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []models.CommitStatus, _param3 []string, _param4 []string, _param5 []string) {
+func (c *MockClient_GetCloneURL_OngoingVerification) GetAllCapturedArguments() (_param0 []models.VCSHostType, _param1 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
- _param0 = make([]models.Repo, len(c.methodInvocations))
+ _param0 = make([]models.VCSHostType, len(c.methodInvocations))
for u, param := range params[0] {
- _param0[u] = param.(models.Repo)
+ _param0[u] = param.(models.VCSHostType)
}
- _param1 = make([]models.PullRequest, len(c.methodInvocations))
+ _param1 = make([]string, len(c.methodInvocations))
for u, param := range params[1] {
- _param1[u] = param.(models.PullRequest)
- }
- _param2 = make([]models.CommitStatus, len(c.methodInvocations))
- for u, param := range params[2] {
- _param2[u] = param.(models.CommitStatus)
- }
- _param3 = make([]string, len(c.methodInvocations))
- for u, param := range params[3] {
- _param3[u] = param.(string)
- }
- _param4 = make([]string, len(c.methodInvocations))
- for u, param := range params[4] {
- _param4[u] = param.(string)
- }
- _param5 = make([]string, len(c.methodInvocations))
- for u, param := range params[5] {
- _param5[u] = param.(string)
+ _param1[u] = param.(string)
}
}
return
diff --git a/server/events/vcs/not_configured_vcs_client.go b/server/events/vcs/not_configured_vcs_client.go
index c470ac7ef6..55a23631d0 100644
--- a/server/events/vcs/not_configured_vcs_client.go
+++ b/server/events/vcs/not_configured_vcs_client.go
@@ -61,7 +61,7 @@ func (a *NotConfiguredVCSClient) SupportsSingleFileDownload(repo models.Repo) bo
return false
}
-func (a *NotConfiguredVCSClient) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) {
+func (a *NotConfiguredVCSClient) GetFileContent(pull models.PullRequest, fileName string) (bool, []byte, error) {
return true, []byte{}, a.err()
}
func (a *NotConfiguredVCSClient) GetCloneURL(VCSHostType models.VCSHostType, repo string) (string, error) {
diff --git a/server/events/vcs/proxy.go b/server/events/vcs/proxy.go
index ddc3e35f28..013092b5c8 100644
--- a/server/events/vcs/proxy.go
+++ b/server/events/vcs/proxy.go
@@ -88,8 +88,8 @@ func (d *ClientProxy) GetTeamNamesForUser(repo models.Repo, user models.User) ([
return d.clients[repo.VCSHost.Type].GetTeamNamesForUser(repo, user)
}
-func (d *ClientProxy) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) {
- return d.clients[pull.BaseRepo.VCSHost.Type].DownloadRepoConfigFile(pull)
+func (d *ClientProxy) GetFileContent(pull models.PullRequest, fileName string) (bool, []byte, error) {
+ return d.clients[pull.BaseRepo.VCSHost.Type].GetFileContent(pull, fileName)
}
func (d *ClientProxy) SupportsSingleFileDownload(repo models.Repo) bool {