feat: add ability to track git untracked files (#3724)

This commit is contained in:
Simon Heather
2023-09-11 15:57:50 +01:00
committed by GitHub
parent 29fef94be7
commit cd7ae114eb
13 changed files with 653 additions and 152 deletions

View File

@@ -97,6 +97,7 @@ const (
GitlabTokenFlag = "gitlab-token"
GitlabUserFlag = "gitlab-user"
GitlabWebhookSecretFlag = "gitlab-webhook-secret" // nolint: gosec
IncludeGitUntrackedFiles = "include-git-untracked-files"
APISecretFlag = "api-secret"
HidePrevPlanComments = "hide-prev-plan-comments"
QuietPolicyChecks = "quiet-policy-checks"
@@ -475,6 +476,10 @@ var boolFlags = map[string]boolFlag{
"VCS support is limited to: GitHub.",
defaultValue: false,
},
IncludeGitUntrackedFiles: {
description: "Include git untracked files in the Atlantis modified file scope.",
defaultValue: false,
},
ParallelPlanFlag: {
description: "Run plan operations in parallel.",
defaultValue: false,

View File

@@ -161,16 +161,17 @@ workflows:
- run: terraform apply $PLANFILE
```
### cdktf
Here are the requirements to enable [cdktf](https://developer.hashicorp.com/terraform/cdktf)
### CDKTF
Here are the requirements to enable [CDKTF](https://developer.hashicorp.com/terraform/cdktf)
- A custom image with `cdktf` installed
- The autoplan file updated to trigger off of `**/cdk.tf.json`
- The output of `cdktf synth` has to be committed to the pull request
- Optional: Use `pre_workflow_hooks` to run `cdktf synth` as a double check
- A custom image with `CDKTF` installed
- Add `**/cdk.tf.json` to the list of Atlantis autoplan files.
- Set the `atlantis-include-git-untracked-files` flag so that the Terraform files dynamically generated
by CDKTF will be add to the Atlantis modified file list.
- Use `pre_workflow_hooks` to run `cdktf synth`
- Optional: There isn't a requirement to use a repo `atlantis.yaml` but one can be leveraged if needed.
#### custom image
#### Custom Image
```dockerfile
# Dockerfile
@@ -179,11 +180,12 @@ FROM ghcr.io/runatlantis/atlantis:v0.19.7
RUN apk add npm && npm i -g cdktf-cli
```
#### server config
#### Server Config
```bash
# env variables
ATLANTIS_AUTOPLAN_FILE_LIST="**/*.tf,**/*.tfvars,**/*.tfvars.json,**/cdk.tf.json"
ATLANTIS_INCLUDE_GIT_UNTRACKED_FILES=true
```
OR
@@ -192,9 +194,10 @@ OR
```yaml
# config.yaml
autoplan-file-list: "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/cdk.tf.json"
include-git-untracked-files: true
```
#### server repo config
#### Server Repo Config
Use `pre_workflow_hooks`
@@ -204,32 +207,39 @@ Use `pre_workflow_hooks`
repos:
- id: /.*cdktf.*/
pre_workflow_hooks:
- run: npm i && cdktf get && cdktf synth
- run: npm i && cdktf get && cdktf synth --output ci-cdktf.out
```
#### repo structure
**Note:** don't use the default `cdktf.out` directory that CDKTF uses, as this should be in the `.gitignore` list of the
repo, so that locally generated files are not checked in.
This is the git repo structure after running `cdktf synth`. The `cdk.tf.json` files contain the HCL that atlantis can run.
#### Repo Structure
This is the git repo structure after running `cdktf synth`. The `cdk.tf.json` files contain the Terraform configuration
that atlantis can run.
```bash
$ tree --gitignore
.
├── cdktf.json
├── cdktf.out
├── ci-cdktf.out
│ ├── manifest.json
│ └── stacks
│ └── eks
│ └── cdk.tf.json
```
#### workflow
#### Workflow
1. Container orchestrator (k8s/fargate/ecs/etc) uses the custom docker image of atlantis with `cdktf` installed with the `--autoplan-file-list` to trigger on json files
1. PR branch is pushed up containing `cdktf` changes and generated hcl json
1. Atlantis checks out the branch in the repo
1. Atlantis runs the `npm i && cdktf get && cdktf synth` command in the repo root as a step in `pre_workflow_hooks` (as a double check described above)
1. Atlantis detects the change to the generated hcl json files in a number of `dir`s
1. Atlantis then runs `terraform` workflows in the respective `dir`s as usual
1. Container orchestrator (k8s/fargate/ecs/etc) uses the custom docker image of atlantis with `cdktf` installed with
the `--autoplan-file-list` to trigger on `cdk.tf.json` files and `--include-git-untracked-files` set to include the
CDKTF dynamically generated Terraform files in the Atlantis plan.
1. PR branch is pushed up containing `cdktf` code changes.
1. Atlantis checks out the branch in the repo.
1. Atlantis runs the `npm i && cdktf get && cdktf synth` command in the repo root as a step in `pre_workflow_hooks`,
generating the `cdk.tf.json` Terraform files.
1. Atlantis detects the `cdk.tf.json` untracked files in a number of directories.
1. Atlantis then runs `terraform` workflows in the respective directories as usual.
### Terragrunt
Atlantis supports running custom commands in place of the default Atlantis

View File

@@ -626,6 +626,16 @@ This is useful when you have many projects and want to keep the pull request cle
Hide previous plan comments to declutter PRs. This is only supported in
GitHub and GitLab currently. This is not enabled by default.
### `--include-git-untracked-files`
```bash
atlantis server --include-git-untracked-files
# or
ATLANTIS_INCLUDE_GIT_UNTRACKED_FILES=true
```
Include git untracked files in the Atlantis modified file list.
Used for example with CDKTF pre-workflow hooks that dynamically generate
Terraform files.
### `--locking-db-type`
```bash
atlantis server --locking-db-type="<boltdb|redis>"

View File

@@ -1323,6 +1323,7 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
false,
false,
statsScope,
logger,
terraformClient,

View File

@@ -93,6 +93,25 @@ func (mock *MockWorkingDir) DeletePlan(r models.Repo, p models.PullRequest, work
return ret0
}
func (mock *MockWorkingDir) GetGitUntrackedFiles(r models.Repo, p models.PullRequest, workspace string) ([]string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockWorkingDir().")
}
params := []pegomock.Param{r, p, workspace}
result := pegomock.GetGenericMockFrom(mock).Invoke("GetGitUntrackedFiles", params, []reflect.Type{reflect.TypeOf((*[]string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []string
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]string)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockWorkingDir) GetPullDir(r models.Repo, p models.PullRequest) (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockWorkingDir().")
@@ -335,6 +354,41 @@ func (c *MockWorkingDir_DeletePlan_OngoingVerification) GetAllCapturedArguments(
return
}
func (verifier *VerifierMockWorkingDir) GetGitUntrackedFiles(r models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification {
params := []pegomock.Param{r, p, workspace}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetGitUntrackedFiles", params, verifier.timeout)
return &MockWorkingDir_GetGitUntrackedFiles_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MockWorkingDir_GetGitUntrackedFiles_OngoingVerification struct {
mock *MockWorkingDir
methodInvocations []pegomock.MethodInvocation
}
func (c *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, string) {
r, p, workspace := c.GetAllCapturedArguments()
return r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1]
}
func (c *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]models.Repo, len(c.methodInvocations))
for u, param := range params[0] {
_param0[u] = param.(models.Repo)
}
_param1 = make([]models.PullRequest, len(c.methodInvocations))
for u, param := range params[1] {
_param1[u] = param.(models.PullRequest)
}
_param2 = make([]string, len(c.methodInvocations))
for u, param := range params[2] {
_param2[u] = param.(string)
}
}
return
}
func (verifier *VerifierMockWorkingDir) GetPullDir(r models.Repo, p models.PullRequest) *MockWorkingDir_GetPullDir_OngoingVerification {
params := []pegomock.Param{r, p}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullDir", params, verifier.timeout)

View File

@@ -93,6 +93,25 @@ func (mock *MockWorkingDir) DeletePlan(r models.Repo, p models.PullRequest, work
return ret0
}
func (mock *MockWorkingDir) GetGitUntrackedFiles(r models.Repo, p models.PullRequest, workspace string) ([]string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockWorkingDir().")
}
params := []pegomock.Param{r, p, workspace}
result := pegomock.GetGenericMockFrom(mock).Invoke("GetGitUntrackedFiles", params, []reflect.Type{reflect.TypeOf((*[]string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []string
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]string)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockWorkingDir) GetPullDir(r models.Repo, p models.PullRequest) (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockWorkingDir().")
@@ -335,6 +354,41 @@ func (c *MockWorkingDir_DeletePlan_OngoingVerification) GetAllCapturedArguments(
return
}
func (verifier *VerifierMockWorkingDir) GetGitUntrackedFiles(r models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification {
params := []pegomock.Param{r, p, workspace}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetGitUntrackedFiles", params, verifier.timeout)
return &MockWorkingDir_GetGitUntrackedFiles_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MockWorkingDir_GetGitUntrackedFiles_OngoingVerification struct {
mock *MockWorkingDir
methodInvocations []pegomock.MethodInvocation
}
func (c *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, string) {
r, p, workspace := c.GetAllCapturedArguments()
return r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1]
}
func (c *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]models.Repo, len(c.methodInvocations))
for u, param := range params[0] {
_param0[u] = param.(models.Repo)
}
_param1 = make([]models.PullRequest, len(c.methodInvocations))
for u, param := range params[1] {
_param1[u] = param.(models.PullRequest)
}
_param2 = make([]string, len(c.methodInvocations))
for u, param := range params[2] {
_param2[u] = param.(string)
}
}
return
}
func (verifier *VerifierMockWorkingDir) GetPullDir(r models.Repo, p models.PullRequest) *MockWorkingDir_GetPullDir_OngoingVerification {
params := []pegomock.Param{r, p}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullDir", params, verifier.timeout)

View File

@@ -53,6 +53,7 @@ func NewInstrumentedProjectCommandBuilder(
AutoplanFileList string,
RestrictFileList bool,
SilenceNoProjects bool,
IncludeGitUntrackedFiles bool,
scope tally.Scope,
logger logging.SimpleLogging,
terraformClient terraform.Client,
@@ -83,6 +84,7 @@ func NewInstrumentedProjectCommandBuilder(
AutoplanFileList,
RestrictFileList,
SilenceNoProjects,
IncludeGitUntrackedFiles,
scope,
logger,
terraformClient,
@@ -111,27 +113,29 @@ func NewProjectCommandBuilder(
AutoplanFileList string,
RestrictFileList bool,
SilenceNoProjects bool,
IncludeGitUntrackedFiles bool,
scope tally.Scope,
logger logging.SimpleLogging,
terraformClient terraform.Client,
) *DefaultProjectCommandBuilder {
return &DefaultProjectCommandBuilder{
ParserValidator: parserValidator,
ProjectFinder: projectFinder,
VCSClient: vcsClient,
WorkingDir: workingDir,
WorkingDirLocker: workingDirLocker,
GlobalCfg: globalCfg,
PendingPlanFinder: pendingPlanFinder,
SkipCloneNoChanges: skipCloneNoChanges,
EnableRegExpCmd: EnableRegExpCmd,
EnableAutoMerge: EnableAutoMerge,
EnableParallelPlan: EnableParallelPlan,
EnableParallelApply: EnableParallelApply,
AutoDetectModuleFiles: AutoDetectModuleFiles,
AutoplanFileList: AutoplanFileList,
RestrictFileList: RestrictFileList,
SilenceNoProjects: SilenceNoProjects,
ParserValidator: parserValidator,
ProjectFinder: projectFinder,
VCSClient: vcsClient,
WorkingDir: workingDir,
WorkingDirLocker: workingDirLocker,
GlobalCfg: globalCfg,
PendingPlanFinder: pendingPlanFinder,
SkipCloneNoChanges: skipCloneNoChanges,
EnableRegExpCmd: EnableRegExpCmd,
EnableAutoMerge: EnableAutoMerge,
EnableParallelPlan: EnableParallelPlan,
EnableParallelApply: EnableParallelApply,
AutoDetectModuleFiles: AutoDetectModuleFiles,
AutoplanFileList: AutoplanFileList,
RestrictFileList: RestrictFileList,
SilenceNoProjects: SilenceNoProjects,
IncludeGitUntrackedFiles: IncludeGitUntrackedFiles,
ProjectCommandContextBuilder: NewProjectCommandContextBuilder(
policyChecksSupported,
commentBuilder,
@@ -184,7 +188,7 @@ type ProjectStateCommandBuilder interface {
BuildStateRmCommands(ctx *command.Context, comment *CommentCommand) ([]command.ProjectContext, error)
}
//go:generate pegomock generate --package mocks -o mocks/mock_project_command_builder.go ProjectCommandBuilder
//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_project_command_builder.go ProjectCommandBuilder
// ProjectCommandBuilder builds commands that run on individual projects.
type ProjectCommandBuilder interface {
@@ -200,25 +204,46 @@ type ProjectCommandBuilder interface {
// This class combines the data from the comment and any atlantis.yaml file or
// Atlantis server config and then generates a set of contexts.
type DefaultProjectCommandBuilder struct {
ParserValidator *config.ParserValidator
ProjectFinder ProjectFinder
VCSClient vcs.Client
WorkingDir WorkingDir
WorkingDirLocker WorkingDirLocker
GlobalCfg valid.GlobalCfg
PendingPlanFinder *DefaultPendingPlanFinder
// Parses and validates server-side repo config files and repo-level atlantis.yaml files.
ParserValidator *config.ParserValidator
// Determines which projects were modified in a given pull request.
ProjectFinder ProjectFinder
// Used to make API calls to a VCS host like GitHub or GitLab.
VCSClient vcs.Client
// Handles the workspace on disk for running commands.
WorkingDir WorkingDir
// Used to prevent multiple commands from executing at the same time for a single repo, pull, and workspace.
WorkingDirLocker WorkingDirLocker
// The final parsed version of the server-side repo config.
GlobalCfg valid.GlobalCfg
// Finds unapplied plans.
PendingPlanFinder *DefaultPendingPlanFinder
// Builds project command contexts for Atlantis commands.
ProjectCommandContextBuilder ProjectCommandContextBuilder
SkipCloneNoChanges bool
EnableRegExpCmd bool
EnableAutoMerge bool
EnableParallelPlan bool
EnableParallelApply bool
AutoDetectModuleFiles string
AutoplanFileList string
EnableDiffMarkdownFormat bool
RestrictFileList bool
SilenceNoProjects bool
TerraformExecutor terraform.Client
// User config option: Skip cloning the repo during autoplan if there are no changes to Terraform projects.
SkipCloneNoChanges bool
// User config option: Enable the use of regular expressions to run plan/apply commands against defined project names.
EnableRegExpCmd bool
// User config option: Automatically merge pull requests after all plans have been successfully applied.
EnableAutoMerge bool
// User config option: Whether to run plan operations in parallel.
EnableParallelPlan bool
// User config option: Whether to run apply operations in parallel.
EnableParallelApply bool
// User config option: Enables auto-planning of projects when a module dependency in the same repository has changed.
AutoDetectModuleFiles string
// User config option: List of file patterns to to to check if a directory contains modified files.
AutoplanFileList string
// User config option: Format Terraform plan output into a markdown-diff friendy format for color-coding purposes.
EnableDiffMarkdownFormat bool
// User config option: Block plan requests from projects outside the files modified in the pull request.
RestrictFileList bool
// User config option: Ignore PR if none of the modified files are part of a project.
SilenceNoProjects bool
// User config option: Include git untracked files in the modified file list.
IncludeGitUntrackedFiles bool
// Handles the actual running of Terraform commands.
TerraformExecutor terraform.Client
}
// See ProjectCommandBuilder.BuildAutoplanCommands.
@@ -241,8 +266,11 @@ func (p *DefaultProjectCommandBuilder) BuildAutoplanCommands(ctx *command.Contex
// See ProjectCommandBuilder.BuildPlanCommands.
func (p *DefaultProjectCommandBuilder) BuildPlanCommands(ctx *command.Context, cmd *CommentCommand) ([]command.ProjectContext, error) {
if !cmd.IsForSpecificProject() {
ctx.Log.Debug("Building plan command for all affected projects")
return p.buildAllCommandsByCfg(ctx, cmd.CommandName(), cmd.SubName, cmd.Flags, cmd.Verbose)
}
ctx.Log.Debug("Building plan command for specific project with directory: '%v', workspace: '%v', project: '%v'",
cmd.RepoRelDir, cmd.Workspace, cmd.ProjectName)
pcc, err := p.buildProjectPlanCommand(ctx, cmd)
return pcc, err
}
@@ -296,7 +324,17 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex
if err != nil {
return nil, err
}
ctx.Log.Debug("%d files were modified in this pull request", len(modifiedFiles))
if p.IncludeGitUntrackedFiles {
ctx.Log.Debug(("'include-git-untracked-files' option is set, getting untracked files"))
untrackedFiles, err := p.WorkingDir.GetGitUntrackedFiles(ctx.HeadRepo, ctx.Pull, DefaultWorkspace)
if err != nil {
return nil, err
}
modifiedFiles = append(modifiedFiles, untrackedFiles...)
}
ctx.Log.Debug("%d files were modified in this pull request. Modified files: %v", len(modifiedFiles), modifiedFiles)
if p.SkipCloneNoChanges && p.VCSClient.SupportsSingleFileDownload(ctx.Pull.BaseRepo) {
repoCfgFile := p.GlobalCfg.RepoConfigFile(ctx.Pull.BaseRepo.ID())
@@ -479,12 +517,25 @@ func (p *DefaultProjectCommandBuilder) buildProjectPlanCommand(ctx *command.Cont
}
if p.RestrictFileList {
ctx.Log.Debug("'restrict-file-list' option is set, checking modified files")
modifiedFiles, err := p.VCSClient.GetModifiedFiles(ctx.Pull.BaseRepo, ctx.Pull)
if err != nil {
return nil, err
}
if p.IncludeGitUntrackedFiles {
ctx.Log.Debug(("'include-git-untracked-files' option is set, getting untracked files"))
untrackedFiles, err := p.WorkingDir.GetGitUntrackedFiles(ctx.HeadRepo, ctx.Pull, workspace)
if err != nil {
return nil, err
}
modifiedFiles = append(modifiedFiles, untrackedFiles...)
}
ctx.Log.Debug("%d files were modified in this pull request. Modified files: %v", len(modifiedFiles), modifiedFiles)
if cmd.RepoRelDir != "" {
ctx.Log.Debug("Command directory specified: %s", cmd.RepoRelDir)
foundDir := false
for _, f := range modifiedFiles {
@@ -499,6 +550,7 @@ func (p *DefaultProjectCommandBuilder) buildProjectPlanCommand(ctx *command.Cont
}
if cmd.ProjectName != "" {
ctx.Log.Debug("Command project name specified: %s", cmd.ProjectName)
var notFoundFiles = []string{}
var repoConfig valid.RepoCfg

View File

@@ -672,6 +672,7 @@ projects:
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
false,
false,
statsScope,
logger,
terraformClient,
@@ -886,6 +887,7 @@ projects:
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
false,
false,
statsScope,
logger,
terraformClient,
@@ -1134,6 +1136,7 @@ workflows:
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
false,
false,
statsScope,
logger,
terraformClient,
@@ -1289,6 +1292,7 @@ projects:
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
true,
false,
statsScope,
logger,
terraformClient,

View File

@@ -22,6 +22,30 @@ import (
. "github.com/runatlantis/atlantis/testing"
)
var defaultUserConfig = struct {
SkipCloneNoChanges bool
EnableRegExpCmd bool
EnableAutoMerge bool
EnableParallelPlan bool
EnableParallelApply bool
AutoDetectModuleFiles string
AutoplanFileList string
RestrictFileList bool
SilenceNoProjects bool
IncludeGitUntrackedFiles bool
}{
SkipCloneNoChanges: false,
EnableRegExpCmd: false,
EnableAutoMerge: false,
EnableParallelPlan: false,
EnableParallelApply: false,
AutoDetectModuleFiles: "",
AutoplanFileList: "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
RestrictFileList: false,
SilenceNoProjects: false,
IncludeGitUntrackedFiles: true,
}
func TestDefaultProjectCommandBuilder_BuildAutoplanCommands(t *testing.T) {
// expCtxFields define the ctx fields we're going to assert on.
// Since we're focused on autoplanning here, we don't validate all the
@@ -122,6 +146,7 @@ projects:
logger := logging.NewNoopLogger(t)
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
userConfig := defaultUserConfig
terraformClient := terraform_mocks.NewMockClient()
When(terraformClient.ListAvailableVersions(Any[logging.SimpleLogging]())).ThenReturn([]string{}, nil)
@@ -159,15 +184,16 @@ projects:
valid.NewGlobalCfgFromArgs(globalCfgArgs),
&events.DefaultPendingPlanFinder{},
&events.CommentParser{ExecutableName: "atlantis"},
false,
false,
false,
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
false,
userConfig.SkipCloneNoChanges,
userConfig.EnableRegExpCmd,
userConfig.EnableAutoMerge,
userConfig.EnableParallelPlan,
userConfig.EnableParallelApply,
userConfig.AutoDetectModuleFiles,
userConfig.AutoplanFileList,
userConfig.RestrictFileList,
userConfig.SilenceNoProjects,
userConfig.IncludeGitUntrackedFiles,
scope,
logger,
terraformClient,
@@ -473,6 +499,7 @@ projects:
logger := logging.NewNoopLogger(t)
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
userConfig := defaultUserConfig
for _, c := range cases {
// NOTE: we're testing both plan and apply here.
@@ -513,15 +540,16 @@ projects:
valid.NewGlobalCfgFromArgs(globalCfgArgs),
&events.DefaultPendingPlanFinder{},
&events.CommentParser{ExecutableName: "atlantis"},
false,
true,
userConfig.SkipCloneNoChanges,
userConfig.EnableRegExpCmd,
c.EnableAutoMergeUserCfg,
c.EnableParallelPlanUserCfg,
c.EnableParallelApplyUserCfg,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
userConfig.AutoDetectModuleFiles,
userConfig.AutoplanFileList,
userConfig.RestrictFileList,
c.Silenced,
userConfig.IncludeGitUntrackedFiles,
scope,
logger,
terraformClient,
@@ -663,6 +691,8 @@ projects:
logger := logging.NewNoopLogger(t)
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
userConfig := defaultUserConfig
userConfig.RestrictFileList = true
for _, c := range cases {
t.Run(c.Description+"_"+command.Plan.String(), func(t *testing.T) {
@@ -699,15 +729,16 @@ projects:
valid.NewGlobalCfgFromArgs(globalCfgArgs),
&events.DefaultPendingPlanFinder{},
&events.CommentParser{ExecutableName: "atlantis"},
false,
true,
false,
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
true,
false,
userConfig.SkipCloneNoChanges,
userConfig.EnableRegExpCmd,
userConfig.EnableAutoMerge,
userConfig.EnableParallelPlan,
userConfig.EnableParallelApply,
userConfig.AutoDetectModuleFiles,
userConfig.AutoplanFileList,
userConfig.RestrictFileList,
userConfig.SilenceNoProjects,
userConfig.IncludeGitUntrackedFiles,
scope,
logger,
terraformClient,
@@ -929,6 +960,8 @@ projects:
logger := logging.NewNoopLogger(t)
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
userConfig := defaultUserConfig
for name, c := range cases {
t.Run(name, func(t *testing.T) {
RegisterMockTestingT(t)
@@ -964,15 +997,16 @@ projects:
valid.NewGlobalCfgFromArgs(globalCfgArgs),
&events.DefaultPendingPlanFinder{},
&events.CommentParser{ExecutableName: "atlantis"},
false,
false,
false,
userConfig.SkipCloneNoChanges,
userConfig.EnableRegExpCmd,
userConfig.EnableAutoMerge,
c.ParallelPlanEnabledUserCfg,
c.ParallelApplyEnabledUserCfg,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
false,
userConfig.AutoDetectModuleFiles,
userConfig.AutoplanFileList,
userConfig.RestrictFileList,
userConfig.SilenceNoProjects,
userConfig.IncludeGitUntrackedFiles,
scope,
logger,
terraformClient,
@@ -1044,6 +1078,7 @@ func TestDefaultProjectCommandBuilder_BuildMultiApply(t *testing.T) {
ThenReturn(tmpDir, nil)
logger := logging.NewNoopLogger(t)
userConfig := defaultUserConfig
globalCfgArgs := valid.GlobalCfgArgs{
AllowRepoCfg: false,
@@ -1066,15 +1101,16 @@ func TestDefaultProjectCommandBuilder_BuildMultiApply(t *testing.T) {
valid.NewGlobalCfgFromArgs(globalCfgArgs),
&events.DefaultPendingPlanFinder{},
&events.CommentParser{ExecutableName: "atlantis"},
false,
false,
false,
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
false,
userConfig.SkipCloneNoChanges,
userConfig.EnableRegExpCmd,
userConfig.EnableAutoMerge,
userConfig.EnableParallelPlan,
userConfig.EnableParallelApply,
userConfig.AutoDetectModuleFiles,
userConfig.AutoplanFileList,
userConfig.RestrictFileList,
userConfig.SilenceNoProjects,
userConfig.IncludeGitUntrackedFiles,
scope,
logger,
terraformClient,
@@ -1145,6 +1181,8 @@ projects:
}
logger := logging.NewNoopLogger(t)
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
userConfig := defaultUserConfig
terraformClient := terraform_mocks.NewMockClient()
When(terraformClient.ListAvailableVersions(Any[logging.SimpleLogging]())).ThenReturn([]string{}, nil)
@@ -1158,15 +1196,16 @@ projects:
valid.NewGlobalCfgFromArgs(globalCfgArgs),
&events.DefaultPendingPlanFinder{},
&events.CommentParser{ExecutableName: "atlantis"},
false,
false,
false,
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
false,
userConfig.SkipCloneNoChanges,
userConfig.EnableRegExpCmd,
userConfig.EnableAutoMerge,
userConfig.EnableParallelPlan,
userConfig.EnableParallelApply,
userConfig.AutoDetectModuleFiles,
userConfig.AutoplanFileList,
userConfig.RestrictFileList,
userConfig.SilenceNoProjects,
userConfig.IncludeGitUntrackedFiles,
scope,
logger,
terraformClient,
@@ -1212,6 +1251,7 @@ func TestDefaultProjectCommandBuilder_EscapeArgs(t *testing.T) {
logger := logging.NewNoopLogger(t)
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
userConfig := defaultUserConfig
for _, c := range cases {
t.Run(strings.Join(c.ExtraArgs, " "), func(t *testing.T) {
@@ -1246,15 +1286,16 @@ func TestDefaultProjectCommandBuilder_EscapeArgs(t *testing.T) {
valid.NewGlobalCfgFromArgs(globalCfgArgs),
&events.DefaultPendingPlanFinder{},
&events.CommentParser{ExecutableName: "atlantis"},
false,
false,
false,
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
false,
userConfig.SkipCloneNoChanges,
userConfig.EnableRegExpCmd,
userConfig.EnableAutoMerge,
userConfig.EnableParallelPlan,
userConfig.EnableParallelApply,
userConfig.AutoDetectModuleFiles,
userConfig.AutoplanFileList,
userConfig.RestrictFileList,
userConfig.SilenceNoProjects,
userConfig.IncludeGitUntrackedFiles,
scope,
logger,
terraformClient,
@@ -1366,6 +1407,7 @@ projects:
logger := logging.NewNoopLogger(t)
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
userConfig := defaultUserConfig
for name, testCase := range testCases {
t.Run(name, func(t *testing.T) {
@@ -1415,15 +1457,16 @@ projects:
valid.NewGlobalCfgFromArgs(globalCfgArgs),
&events.DefaultPendingPlanFinder{},
&events.CommentParser{ExecutableName: "atlantis"},
false,
false,
false,
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
false,
userConfig.SkipCloneNoChanges,
userConfig.EnableRegExpCmd,
userConfig.EnableAutoMerge,
userConfig.EnableParallelPlan,
userConfig.EnableParallelApply,
userConfig.AutoDetectModuleFiles,
userConfig.AutoplanFileList,
userConfig.RestrictFileList,
userConfig.SilenceNoProjects,
userConfig.IncludeGitUntrackedFiles,
scope,
logger,
terraformClient,
@@ -1482,6 +1525,9 @@ parallel_plan: true`,
},
}
userConfig := defaultUserConfig
userConfig.SkipCloneNoChanges = true
for _, c := range cases {
RegisterMockTestingT(t)
vcsClient := vcsmocks.NewMockClient()
@@ -1512,15 +1558,16 @@ parallel_plan: true`,
valid.NewGlobalCfgFromArgs(globalCfgArgs),
&events.DefaultPendingPlanFinder{},
&events.CommentParser{ExecutableName: "atlantis"},
true,
false,
false,
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
false,
userConfig.SkipCloneNoChanges,
userConfig.EnableRegExpCmd,
userConfig.EnableAutoMerge,
userConfig.EnableParallelPlan,
userConfig.EnableParallelApply,
userConfig.AutoDetectModuleFiles,
userConfig.AutoplanFileList,
userConfig.RestrictFileList,
userConfig.SilenceNoProjects,
userConfig.IncludeGitUntrackedFiles,
scope,
logger,
terraformClient,
@@ -1552,6 +1599,7 @@ func TestDefaultProjectCommandBuilder_WithPolicyCheckEnabled_BuildAutoplanComman
logger := logging.NewNoopLogger(t)
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
userConfig := defaultUserConfig
workingDir := mocks.NewMockWorkingDir()
When(workingDir.Clone(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, false, nil)
@@ -1580,15 +1628,16 @@ func TestDefaultProjectCommandBuilder_WithPolicyCheckEnabled_BuildAutoplanComman
globalCfg,
&events.DefaultPendingPlanFinder{},
&events.CommentParser{ExecutableName: "atlantis"},
false,
false,
false,
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
false,
userConfig.SkipCloneNoChanges,
userConfig.EnableRegExpCmd,
userConfig.EnableAutoMerge,
userConfig.EnableParallelPlan,
userConfig.EnableParallelApply,
userConfig.AutoDetectModuleFiles,
userConfig.AutoplanFileList,
userConfig.RestrictFileList,
userConfig.SilenceNoProjects,
userConfig.IncludeGitUntrackedFiles,
scope,
logger,
terraformClient,
@@ -1650,6 +1699,7 @@ func TestDefaultProjectCommandBuilder_BuildVersionCommand(t *testing.T) {
logger := logging.NewNoopLogger(t)
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
userConfig := defaultUserConfig
globalCfgArgs := valid.GlobalCfgArgs{
AllowRepoCfg: false,
@@ -1670,15 +1720,16 @@ func TestDefaultProjectCommandBuilder_BuildVersionCommand(t *testing.T) {
valid.NewGlobalCfgFromArgs(globalCfgArgs),
&events.DefaultPendingPlanFinder{},
&events.CommentParser{ExecutableName: "atlantis"},
false,
false,
false,
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
false,
userConfig.SkipCloneNoChanges,
userConfig.EnableRegExpCmd,
userConfig.EnableAutoMerge,
userConfig.EnableParallelPlan,
userConfig.EnableParallelApply,
userConfig.AutoDetectModuleFiles,
userConfig.AutoplanFileList,
userConfig.RestrictFileList,
userConfig.SilenceNoProjects,
userConfig.IncludeGitUntrackedFiles,
scope,
logger,
terraformClient,
@@ -1708,3 +1759,238 @@ func TestDefaultProjectCommandBuilder_BuildVersionCommand(t *testing.T) {
Equals(t, "project2", ctxs[3].RepoRelDir)
Equals(t, "workspace2", ctxs[3].Workspace)
}
// Test
func TestDefaultProjectCommandBuilder_BuildPlanCommands_Single_With_RestrictFileList_And_IncludeGitUntrackedFiles(t *testing.T) {
testDir1 := "directory-1"
testDir2 := "directory-2"
cases := []struct {
Description string
AtlantisYAML string
DirectoryStructure map[string]interface{}
ModifiedFiles []string
UntrackedFiles []string
Cmd events.CommentCommand
ExpRepoRelDir string
ExpErr string
}{
{
Description: "planning a git untracked file project in a modified directory",
Cmd: events.CommentCommand{
Name: command.Plan,
RepoRelDir: testDir1 + "/ci-cdktf.out/stacks/test",
Workspace: "default",
},
DirectoryStructure: map[string]interface{}{
testDir1: map[string]interface{}{
"main.ts": nil,
},
},
ModifiedFiles: []string{testDir1 + "/main.ts"},
UntrackedFiles: []string{testDir1 + "/ci-cdktf.out/stacks/test/cdk.tf.json"},
ExpRepoRelDir: testDir1 + "/ci-cdktf.out/stacks/test",
},
{
Description: "planning a git untracked file project outside a modified directory",
Cmd: events.CommentCommand{
Name: command.Plan,
RepoRelDir: testDir2 + "/ci-cdktf.out/stacks/test",
Workspace: "default",
},
DirectoryStructure: map[string]interface{}{
testDir1: map[string]interface{}{
"main.ts": nil,
},
},
ModifiedFiles: []string{testDir1 + "/main.ts"},
UntrackedFiles: []string{testDir1 + "/ci-cdktf.out/stacks/test/cdk.tf.json"},
ExpErr: "the dir \"" + testDir2 + "/ci-cdktf.out/stacks/test\" is not in the plan list of this pull request",
},
}
globalCfgArgs := valid.GlobalCfgArgs{
AllowRepoCfg: true,
MergeableReq: false,
ApprovedReq: false,
UnDivergedReq: false,
}
logger := logging.NewNoopLogger(t)
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
userConfig := defaultUserConfig
userConfig.RestrictFileList = true
userConfig.IncludeGitUntrackedFiles = true
for _, c := range cases {
t.Run(c.Description+"_"+command.Plan.String(), func(t *testing.T) {
RegisterMockTestingT(t)
tmpDir := DirStructure(t, c.DirectoryStructure)
workingDir := mocks.NewMockWorkingDir()
When(workingDir.Clone(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, false, nil)
When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil)
When(workingDir.GetGitUntrackedFiles(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(c.UntrackedFiles, nil)
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(c.ModifiedFiles, nil)
if c.AtlantisYAML != "" {
err := os.WriteFile(filepath.Join(tmpDir, valid.DefaultAtlantisFile), []byte(c.AtlantisYAML), 0600)
Ok(t, err)
}
terraformClient := terraform_mocks.NewMockClient()
When(terraformClient.ListAvailableVersions(Any[logging.SimpleLogging]())).ThenReturn([]string{}, nil)
builder := events.NewProjectCommandBuilder(
false, // policyChecksSupported
&config.ParserValidator{},
&events.DefaultProjectFinder{},
vcsClient,
workingDir,
events.NewDefaultWorkingDirLocker(),
valid.NewGlobalCfgFromArgs(globalCfgArgs),
&events.DefaultPendingPlanFinder{},
&events.CommentParser{ExecutableName: "atlantis"},
userConfig.SkipCloneNoChanges,
userConfig.EnableRegExpCmd,
userConfig.EnableAutoMerge,
userConfig.EnableParallelPlan,
userConfig.EnableParallelApply,
userConfig.AutoDetectModuleFiles,
userConfig.AutoplanFileList,
userConfig.RestrictFileList,
userConfig.SilenceNoProjects,
userConfig.IncludeGitUntrackedFiles,
scope,
logger,
terraformClient,
)
var actCtxs []command.ProjectContext
var err error
actCtxs, err = builder.BuildPlanCommands(&command.Context{
Log: logger,
Scope: scope,
}, &c.Cmd)
if c.ExpErr != "" {
ErrEquals(t, c.ExpErr, err)
return
}
Ok(t, err)
Equals(t, 1, len(actCtxs))
actCtx := actCtxs[0]
Equals(t, c.ExpRepoRelDir, actCtx.RepoRelDir)
})
}
}
func TestDefaultProjectCommandBuilder_BuildPlanCommands_with_IncludeGitUntrackedFiles(t *testing.T) {
testDir1 := "directory-1"
cases := []struct {
Description string
AtlantisYAML string
DirectoryStructure map[string]interface{}
ModifiedFiles []string
UntrackedFiles []string
Cmd events.CommentCommand
ExpRepoRelDir string
ExpErr string
}{
{
Description: "planning with a git untracked file",
Cmd: events.CommentCommand{
Name: command.Plan,
},
DirectoryStructure: map[string]interface{}{
testDir1: map[string]interface{}{
"main.ts": nil,
"ci-cdktf.out": map[string]interface{}{
"stacks": map[string]interface{}{
"test": map[string]interface{}{
"cdk.tf.json": nil,
},
},
},
},
},
ModifiedFiles: []string{testDir1 + "/main.ts"},
UntrackedFiles: []string{testDir1 + "/ci-cdktf.out/stacks/test/cdk.tf.json"},
ExpRepoRelDir: testDir1 + "/ci-cdktf.out/stacks/test",
},
}
globalCfgArgs := valid.GlobalCfgArgs{
AllowRepoCfg: true,
MergeableReq: false,
ApprovedReq: false,
UnDivergedReq: false,
}
logger := logging.NewNoopLogger(t)
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
userConfig := defaultUserConfig
userConfig.IncludeGitUntrackedFiles = true
userConfig.AutoplanFileList = "**/cdk.tf.json"
for _, c := range cases {
t.Run(c.Description+"_"+command.Plan.String(), func(t *testing.T) {
RegisterMockTestingT(t)
tmpDir := DirStructure(t, c.DirectoryStructure)
workingDir := mocks.NewMockWorkingDir()
When(workingDir.Clone(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, false, nil)
When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil)
When(workingDir.GetGitUntrackedFiles(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(c.UntrackedFiles, nil)
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(c.ModifiedFiles, nil)
if c.AtlantisYAML != "" {
err := os.WriteFile(filepath.Join(tmpDir, valid.DefaultAtlantisFile), []byte(c.AtlantisYAML), 0600)
Ok(t, err)
}
terraformClient := terraform_mocks.NewMockClient()
When(terraformClient.ListAvailableVersions(Any[logging.SimpleLogging]())).ThenReturn([]string{}, nil)
builder := events.NewProjectCommandBuilder(
false, // policyChecksSupported
&config.ParserValidator{},
&events.DefaultProjectFinder{},
vcsClient,
workingDir,
events.NewDefaultWorkingDirLocker(),
valid.NewGlobalCfgFromArgs(globalCfgArgs),
&events.DefaultPendingPlanFinder{},
&events.CommentParser{ExecutableName: "atlantis"},
userConfig.SkipCloneNoChanges,
userConfig.EnableRegExpCmd,
userConfig.EnableAutoMerge,
userConfig.EnableParallelPlan,
userConfig.EnableParallelApply,
userConfig.AutoDetectModuleFiles,
userConfig.AutoplanFileList,
userConfig.RestrictFileList,
userConfig.SilenceNoProjects,
userConfig.IncludeGitUntrackedFiles,
scope,
logger,
terraformClient,
)
var actCtxs []command.ProjectContext
var err error
actCtxs, err = builder.BuildPlanCommands(&command.Context{
Log: logger,
Scope: scope,
}, &c.Cmd)
if c.ExpErr != "" {
ErrEquals(t, c.ExpErr, err)
return
}
Ok(t, err)
Equals(t, 1, len(actCtxs))
actCtx := actCtxs[0]
Equals(t, c.ExpRepoRelDir, actCtx.RepoRelDir)
})
}
}

View File

@@ -144,7 +144,7 @@ func (p *DefaultProjectFinder) DetermineProjects(log logging.SimpleLogging, modi
if len(modifiedTerraformFiles) == 0 {
return projects
}
log.Info("filtered modified files to %d .tf or terragrunt.hcl files: %v",
log.Info("filtered modified files to %d file(s) in the autoplan file list: %v",
len(modifiedTerraformFiles), modifiedTerraformFiles)
var dirs []string

View File

@@ -32,8 +32,8 @@ const workingDirPrefix = "repos"
var cloneLocks sync.Map
//go:generate pegomock generate --package mocks -o mocks/mock_working_dir.go WorkingDir
//go:generate pegomock generate --package events WorkingDir
//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_working_dir.go WorkingDir
//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package events WorkingDir
// WorkingDir handles the workspace on disk for running commands.
type WorkingDir interface {
@@ -56,6 +56,8 @@ type WorkingDir interface {
SetSafeToReClone()
// DeletePlan deletes the plan for this repo, pull, workspace path and project name
DeletePlan(r models.Repo, p models.PullRequest, workspace string, path string, projectName string) error
// GetGitUntrackedFiles returns a list of Git untracked files in the working dir.
GetGitUntrackedFiles(r models.Repo, p models.PullRequest, workspace string) ([]string, error)
}
// FileWorkspace implements WorkingDir with the file system.
@@ -382,3 +384,24 @@ func (w *FileWorkspace) DeletePlan(r models.Repo, p models.PullRequest, workspac
w.Logger.Info("Deleting plan: " + planPath)
return os.Remove(planPath)
}
// getGitUntrackedFiles returns a list of Git untracked files in the working dir.
func (w *FileWorkspace) GetGitUntrackedFiles(r models.Repo, p models.PullRequest, workspace string) ([]string, error) {
workingDir, err := w.GetWorkingDir(r, p, workspace)
if err != nil {
return nil, err
}
w.Logger.Debug("Checking for Git untracked files in directory: '%s'", workingDir)
cmd := exec.Command("git", "ls-files", "--others", "--exclude-standard")
cmd.Dir = workingDir
output, err := cmd.CombinedOutput()
if err != nil {
return nil, err
}
untrackedFiles := strings.Split(string(output), "\n")[:]
w.Logger.Debug("Untracked files: '%s'", strings.Join(untrackedFiles, ","))
return untrackedFiles, nil
}

View File

@@ -596,6 +596,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
userConfig.AutoplanFileList,
userConfig.RestrictFileList,
userConfig.SilenceNoProjects,
userConfig.IncludeGitUntrackedFiles,
statsScope,
logger,
terraformClient,

View File

@@ -60,6 +60,7 @@ type UserConfig struct {
GitlabToken string `mapstructure:"gitlab-token"`
GitlabUser string `mapstructure:"gitlab-user"`
GitlabWebhookSecret string `mapstructure:"gitlab-webhook-secret"`
IncludeGitUntrackedFiles bool `mapstructure:"include-git-untracked-files"`
APISecret string `mapstructure:"api-secret"`
HidePrevPlanComments bool `mapstructure:"hide-prev-plan-comments"`
LockingDBType string `mapstructure:"locking-db-type"`