Skip to content
This repository was archived by the owner on May 11, 2022. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,8 @@ env:
- CGO_ENABLED=0
builds:
- targets:
- darwin_amd64
- darwin_arm64
- linux_386
- linux_amd64
- linux_arm
- linux_arm64
- windows_386
- windows_amd64

archives:
- id: zip
Expand All @@ -26,7 +20,7 @@ changelog:

release:
github:
owner: runatlantis
owner: edgelaboratories
name: atlantis
draft: true

Expand Down
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ FROM ghcr.io/runatlantis/atlantis-base:2022.03.04 AS base
ARG TARGETPLATFORM

# install terraform binaries
ENV DEFAULT_TERRAFORM_VERSION=1.1.7
ENV DEFAULT_TERRAFORM_VERSION=1.1.8

# In the official Atlantis image we only have the latest of each Terraform version.
RUN AVAILABLE_TERRAFORM_VERSIONS="0.11.15 0.12.31 0.13.7 0.14.11 0.15.5 1.0.11 ${DEFAULT_TERRAFORM_VERSION}" && \
# In this Atlantis image we only have the latest Terraform version.
RUN AVAILABLE_TERRAFORM_VERSIONS="${DEFAULT_TERRAFORM_VERSION}" && \
case ${TARGETPLATFORM} in \
"linux/amd64") TERRAFORM_ARCH=amd64 ;; \
"linux/arm64") TERRAFORM_ARCH=arm64 ;; \
Expand Down
4 changes: 4 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!groovy
@Library('EdgeLabJenkins@master') _

dockerPipeline("atlantis", "default", false, true)
15 changes: 7 additions & 8 deletions server/controllers/github_app_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ import (

// GithubAppController handles the creation and setup of a new GitHub app
type GithubAppController struct {
AtlantisURL *url.URL
Logger logging.SimpleLogging
GithubSetupComplete bool
GithubHostname string
GithubOrg string
AtlantisURL *url.URL
Logger logging.SimpleLogging
GithubSetupComplete bool
GithubHostname string
GithubOrg string
AtlantisYAMLFilename string
}

type githubWebhook struct {
Expand All @@ -42,7 +43,6 @@ type githubAppRequest struct {
// A code query parameter is exchanged for this app's ID, key, and webhook_secret
// Implements https://developer.github.com/apps/building-github-apps/creating-github-apps-from-a-manifest/#implementing-the-github-app-manifest-flow
func (g *GithubAppController) ExchangeCode(w http.ResponseWriter, r *http.Request) {

if g.GithubSetupComplete {
g.respond(w, logging.Error, http.StatusBadRequest, "Atlantis already has GitHub credentials")
return
Expand All @@ -55,7 +55,7 @@ func (g *GithubAppController) ExchangeCode(w http.ResponseWriter, r *http.Reques

g.Logger.Debug("Exchanging GitHub app code for app credentials")
creds := &vcs.GithubAnonymousCredentials{}
client, err := vcs.NewGithubClient(g.GithubHostname, creds, g.Logger)
client, err := vcs.NewGithubClient(g.GithubHostname, creds, g.Logger, g.AtlantisYAMLFilename)
if err != nil {
g.respond(w, logging.Error, http.StatusInternalServerError, "Failed to exchange code for github app: %s", err)
return
Expand Down Expand Up @@ -84,7 +84,6 @@ func (g *GithubAppController) ExchangeCode(w http.ResponseWriter, r *http.Reques

// New redirects the user to create a new GitHub app
func (g *GithubAppController) New(w http.ResponseWriter, r *http.Request) {

if g.GithubSetupComplete {
g.respond(w, logging.Error, http.StatusBadRequest, "Atlantis already has GitHub credentials")
return
Expand Down
29 changes: 21 additions & 8 deletions server/core/config/parser_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,26 @@ import (
yaml "gopkg.in/yaml.v2"
)

// AtlantisYAMLFilename is the name of the config file for each repo.
const AtlantisYAMLFilename = "atlantis.yaml"
// DefaultAtlantisYAMLFilename is the name of the config file for each repo.
const DefaultAtlantisYAMLFilename = "atlantis.yaml"

// ParserValidator parses and validates server-side repo config files and
// repo-level atlantis.yaml files.
type ParserValidator struct{}
type ParserValidator struct {
AtlantisYAMLFilename string
}

// NewParserValidator creates a validator to parse the configuration.
func NewParserValidator(atlantisYAMLFilenames ...string) *ParserValidator {
atlantisYAMLFilename := DefaultAtlantisYAMLFilename
if len(atlantisYAMLFilenames) != 0 && atlantisYAMLFilenames[0] != "" {
Copy link
Author

@greut greut May 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

atlantisYAMLFilename = atlantisYAMLFilenames[0]
}

return &ParserValidator{
AtlantisYAMLFilename: atlantisYAMLFilename,
}
}

// HasRepoCfg returns true if there is a repo config (atlantis.yaml) file
// for the repo at absRepoDir.
Expand All @@ -30,10 +44,10 @@ func (p *ParserValidator) HasRepoCfg(absRepoDir string) (bool, error) {
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 - %q", invalidExtensionFilename, p.AtlantisYAMLFilename)
}

_, err = os.Stat(p.repoCfgPath(absRepoDir, AtlantisYAMLFilename))
_, err = os.Stat(p.repoCfgPath(absRepoDir, p.AtlantisYAMLFilename))
if os.IsNotExist(err) {
return false, nil
}
Expand All @@ -44,12 +58,11 @@ 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) (valid.RepoCfg, error) {
configFile := p.repoCfgPath(absRepoDir, AtlantisYAMLFilename)
configFile := p.repoCfgPath(absRepoDir, p.AtlantisYAMLFilename)
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", p.AtlantisYAMLFilename)
}
// Don't wrap os.IsNotExist errors because we want our callers to be
// able to detect if it's a NotExist err.
Expand Down
40 changes: 20 additions & 20 deletions server/core/config/parser_validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var globalCfgArgs = valid.GlobalCfgArgs{
var globalCfg = valid.NewGlobalCfgFromArgs(globalCfgArgs)

func TestHasRepoCfg_DirDoesNotExist(t *testing.T) {
r := config.ParserValidator{}
r := config.NewParserValidator()
exists, err := r.HasRepoCfg("/not/exist")
Ok(t, err)
Equals(t, false, exists)
Expand All @@ -33,7 +33,7 @@ func TestHasRepoCfg_DirDoesNotExist(t *testing.T) {
func TestHasRepoCfg_FileDoesNotExist(t *testing.T) {
tmpDir, cleanup := TempDir(t)
defer cleanup()
r := config.ParserValidator{}
r := config.NewParserValidator()
exists, err := r.HasRepoCfg(tmpDir)
Ok(t, err)
Equals(t, false, exists)
Expand All @@ -45,32 +45,32 @@ func TestHasRepoCfg_InvalidFileExtension(t *testing.T) {
_, err := os.Create(filepath.Join(tmpDir, "atlantis.yml"))
Ok(t, err)

r := config.ParserValidator{}
r := config.NewParserValidator()
_, err = r.HasRepoCfg(tmpDir)
ErrContains(t, "found \"atlantis.yml\" as config file; rename using the .yaml extension - \"atlantis.yaml\"", err)
}

func TestParseRepoCfg_DirDoesNotExist(t *testing.T) {
r := config.ParserValidator{}
r := config.NewParserValidator()
_, err := r.ParseRepoCfg("/not/exist", globalCfg, "")
Assert(t, os.IsNotExist(err), "exp not exist err")
}

func TestParseRepoCfg_FileDoesNotExist(t *testing.T) {
tmpDir, cleanup := TempDir(t)
defer cleanup()
r := config.ParserValidator{}
r := config.NewParserValidator()
_, err := r.ParseRepoCfg(tmpDir, globalCfg, "")
Assert(t, os.IsNotExist(err), "exp not exist err")
}

func TestParseRepoCfg_BadPermissions(t *testing.T) {
tmpDir, cleanup := TempDir(t)
defer cleanup()
err := os.WriteFile(filepath.Join(tmpDir, "atlantis.yaml"), nil, 0000)
err := os.WriteFile(filepath.Join(tmpDir, "atlantis.yaml"), nil, 0o000)
Ok(t, err)

r := config.ParserValidator{}
r := config.NewParserValidator()
_, err = r.ParseRepoCfg(tmpDir, globalCfg, "")
ErrContains(t, "unable to read atlantis.yaml file: ", err)
}
Expand Down Expand Up @@ -102,9 +102,9 @@ func TestParseCfgs_InvalidYAML(t *testing.T) {
for _, c := range cases {
t.Run(c.description, func(t *testing.T) {
confPath := filepath.Join(tmpDir, "atlantis.yaml")
err := os.WriteFile(confPath, []byte(c.input), 0600)
err := os.WriteFile(confPath, []byte(c.input), 0o600)
Ok(t, err)
r := config.ParserValidator{}
r := config.NewParserValidator()
_, err = r.ParseRepoCfg(tmpDir, globalCfg, "")
ErrContains(t, c.expErr, err)
globalCfgArgs := valid.GlobalCfgArgs{
Expand Down Expand Up @@ -1067,10 +1067,10 @@ workflows:

for _, c := range cases {
t.Run(c.description, func(t *testing.T) {
err := os.WriteFile(filepath.Join(tmpDir, "atlantis.yaml"), []byte(c.input), 0600)
err := os.WriteFile(filepath.Join(tmpDir, "atlantis.yaml"), []byte(c.input), 0o600)
Ok(t, err)

r := config.ParserValidator{}
r := config.NewParserValidator()
act, err := r.ParseRepoCfg(tmpDir, globalCfg, "")
if c.expErr != "" {
ErrEquals(t, c.expErr, err)
Expand All @@ -1095,10 +1095,10 @@ projects:
workflow: custom
workflows:
custom: ~`
err := os.WriteFile(filepath.Join(tmpDir, "atlantis.yaml"), []byte(repoCfg), 0600)
err := os.WriteFile(filepath.Join(tmpDir, "atlantis.yaml"), []byte(repoCfg), 0o600)
Ok(t, err)

r := config.ParserValidator{}
r := config.NewParserValidator()
globalCfgArgs := valid.GlobalCfgArgs{
AllowRepoCfg: false,
MergeableReq: false,
Expand All @@ -1111,7 +1111,7 @@ workflows:
}

func TestParseGlobalCfg_NotExist(t *testing.T) {
r := config.ParserValidator{}
r := config.NewParserValidator()
globalCfgArgs := valid.GlobalCfgArgs{
AllowRepoCfg: false,
MergeableReq: false,
Expand Down Expand Up @@ -1481,11 +1481,11 @@ workflows:

for name, c := range cases {
t.Run(name, func(t *testing.T) {
r := config.ParserValidator{}
r := config.NewParserValidator()
tmp, cleanup := TempDir(t)
defer cleanup()
path := filepath.Join(tmp, "conf.yaml")
Ok(t, os.WriteFile(path, []byte(c.input), 0600))
Ok(t, os.WriteFile(path, []byte(c.input), 0o600))

globalCfgArgs := valid.GlobalCfgArgs{
AllowRepoCfg: false,
Expand Down Expand Up @@ -1682,7 +1682,7 @@ func TestParserValidator_ParseGlobalCfgJSON(t *testing.T) {
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
pv := &config.ParserValidator{}
pv := config.NewParserValidator()
globalCfgArgs := valid.GlobalCfgArgs{
AllowRepoCfg: false,
MergeableReq: false,
Expand Down Expand Up @@ -1746,10 +1746,10 @@ func TestParseRepoCfg_V2ShellParsing(t *testing.T) {
apply:
steps:
- run: %s`, c.in, c.in)
Ok(t, os.WriteFile(v2Path, []byte("version: 2\n"+cfg), 0600))
Ok(t, os.WriteFile(v3Path, []byte("version: 3\n"+cfg), 0600))
Ok(t, os.WriteFile(v2Path, []byte("version: 2\n"+cfg), 0o600))
Ok(t, os.WriteFile(v3Path, []byte("version: 3\n"+cfg), 0o600))

p := &config.ParserValidator{}
p := config.NewParserValidator()
globalCfgArgs := valid.GlobalCfgArgs{
AllowRepoCfg: true,
MergeableReq: false,
Expand Down
8 changes: 4 additions & 4 deletions server/core/config/valid/global_cfg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -661,15 +661,15 @@ policies:
var global valid.GlobalCfg
if c.gCfg != "" {
path := filepath.Join(tmp, "config.yaml")
Ok(t, os.WriteFile(path, []byte(c.gCfg), 0600))
Ok(t, os.WriteFile(path, []byte(c.gCfg), 0o600))
var err error
globalCfgArgs := valid.GlobalCfgArgs{
AllowRepoCfg: false,
MergeableReq: false,
ApprovedReq: false,
UnDivergedReq: false,
}
global, err = (&config.ParserValidator{}).ParseGlobalCfg(path, valid.NewGlobalCfgFromArgs(globalCfgArgs))
global, err = config.NewParserValidator().ParseGlobalCfg(path, valid.NewGlobalCfgFromArgs(globalCfgArgs))
Ok(t, err)
} else {
globalCfgArgs := valid.GlobalCfgArgs{
Expand Down Expand Up @@ -832,7 +832,7 @@ repos:
var global valid.GlobalCfg
if c.gCfg != "" {
path := filepath.Join(tmp, "config.yaml")
Ok(t, os.WriteFile(path, []byte(c.gCfg), 0600))
Ok(t, os.WriteFile(path, []byte(c.gCfg), 0o600))
var err error
globalCfgArgs := valid.GlobalCfgArgs{
AllowRepoCfg: false,
Expand All @@ -841,7 +841,7 @@ repos:
UnDivergedReq: false,
}

global, err = (&config.ParserValidator{}).ParseGlobalCfg(path, valid.NewGlobalCfgFromArgs(globalCfgArgs))
global, err = config.NewParserValidator().ParseGlobalCfg(path, valid.NewGlobalCfgFromArgs(globalCfgArgs))
Ok(t, err)
} else {
globalCfgArgs := valid.GlobalCfgArgs{
Expand Down
9 changes: 4 additions & 5 deletions server/events/comment_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,15 +190,15 @@ func (e *CommentParser) Parse(comment string, vcsHost models.VCSHostType) Commen
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, "", 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.DefaultAtlantisYAMLFilename))
flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.")
case command.Apply.String():
name = command.Apply
flagSet = pflag.NewFlagSet(command.Apply.String(), pflag.ContinueOnError)
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, "", 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.DefaultAtlantisYAMLFilename))
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():
Expand All @@ -215,7 +215,7 @@ func (e *CommentParser) Parse(comment string, vcsHost models.VCSHostType) Commen
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, "", fmt.Sprintf("Print the version for this project. Refers to the name of the project configured in %s.", config.DefaultAtlantisYAMLFilename))
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)}
Expand Down Expand Up @@ -368,7 +368,7 @@ func (e *CommentParser) errMarkdown(errMsg string, cmd string, flagSet *pflag.Fl

func (e *CommentParser) HelpComment(applyDisabled bool) string {
buf := &bytes.Buffer{}
var tmpl = template.Must(template.New("").Parse(helpCommentTemplate))
tmpl := template.Must(template.New("").Parse(helpCommentTemplate))
if err := tmpl.Execute(buf, struct {
ApplyDisabled bool
}{
Expand All @@ -377,7 +377,6 @@ func (e *CommentParser) HelpComment(applyDisabled bool) string {
return fmt.Sprintf("Failed to render template, this is a bug: %v", err)
}
return buf.String()

}

var helpCommentTemplate = "```cmake\n" +
Expand Down
Loading