Test BuildAutoplanCommands

This commit is contained in:
Luke Kysow
2018-06-29 14:34:05 +02:00
parent 12f071b237
commit 6f8401d57b
11 changed files with 535 additions and 117 deletions

View File

@@ -215,7 +215,7 @@ func (e *CommentParser) Parse(comment string, vcsHost models.VCSHostType) Commen
}
return CommentParseResult{
Command: NewCommand(dir, extraArgs, name, verbose, workspace, project),
Command: NewCommentCommand(dir, extraArgs, name, verbose, workspace, project),
}
}

View File

@@ -85,8 +85,8 @@ func (c CommentCommand) String() string {
return fmt.Sprintf("command=%q verbose=%t dir=%q workspace=%q project=%q flags=%q", c.Name.String(), c.Verbose, c.Dir, c.Workspace, c.ProjectName, strings.Join(c.Flags, ","))
}
// NewCommand constructs a Command, setting all missing fields to defaults.
func NewCommand(dir string, flags []string, name CommandName, verbose bool, workspace string, project string) *CommentCommand {
// NewCommentCommand constructs a CommentCommand, setting all missing fields to defaults.
func NewCommentCommand(dir string, flags []string, name CommandName, verbose bool, workspace string, project string) *CommentCommand {
// If dir was an empty string, this will return '.'.
validDir := path.Clean(dir)
if validDir == "/" {

View File

@@ -344,19 +344,19 @@ func TestNewCommand_CleansDir(t *testing.T) {
for _, c := range cases {
t.Run(c.Dir, func(t *testing.T) {
cmd := events.NewCommand(c.Dir, nil, events.Plan, false, "workspace", "")
cmd := events.NewCommentCommand(c.Dir, nil, events.Plan, false, "workspace", "")
Equals(t, c.ExpDir, cmd.Dir)
})
}
}
func TestNewCommand_EmptyWorkspace(t *testing.T) {
cmd := events.NewCommand("dir", nil, events.Plan, false, "", "")
cmd := events.NewCommentCommand("dir", nil, events.Plan, false, "", "")
Equals(t, "default", cmd.Workspace)
}
func TestNewCommand_AllFieldsSet(t *testing.T) {
cmd := events.NewCommand("dir", []string{"a", "b"}, events.Plan, true, "workspace", "project")
cmd := events.NewCommentCommand("dir", []string{"a", "b"}, events.Plan, true, "workspace", "project")
Equals(t, events.CommentCommand{
Workspace: "workspace",
Dir: "dir",

View File

@@ -237,6 +237,5 @@ type ProjectCommandContext struct {
// ex. atlantis plan -- -target=resource
CommentArgs []string
Workspace string
ProjectName string
RequireApprovalOverride bool
}

View File

@@ -88,7 +88,6 @@ func (p *DefaultProjectCommandBuilder) BuildAutoplanCommands(ctx *CommandContext
User: ctx.User,
Log: ctx.Log,
RepoRelPath: mp.Path,
ProjectName: "",
ProjectConfig: nil,
GlobalConfig: nil,
CommentArgs: nil,
@@ -108,10 +107,6 @@ func (p *DefaultProjectCommandBuilder) BuildAutoplanCommands(ctx *CommandContext
// project config.
for i := 0; i < len(matchingProjects); i++ {
mp := matchingProjects[i]
var projectName string
if mp.Name != nil {
projectName = *mp.Name
}
projCtxs = append(projCtxs, models.ProjectCommandContext{
BaseRepo: ctx.BaseRepo,
HeadRepo: ctx.HeadRepo,
@@ -121,7 +116,6 @@ func (p *DefaultProjectCommandBuilder) BuildAutoplanCommands(ctx *CommandContext
CommentArgs: nil,
Workspace: mp.Workspace,
RepoRelPath: mp.Dir,
ProjectName: projectName,
ProjectConfig: &mp,
GlobalConfig: &config,
})
@@ -144,100 +138,88 @@ func (p *DefaultProjectCommandBuilder) BuildPlanCommand(ctx *CommandContext, cmd
return projCtx, err
}
var projCfg *valid.Project
var globalCfg *valid.Spec
// Parse config file if it exists.
config, err := p.ParserValidator.ReadConfig(repoDir)
if err != nil && !os.IsNotExist(err) {
return projCtx, err
}
hasAtlantisYAML := !os.IsNotExist(err)
if hasAtlantisYAML {
// If they've specified a project by name we look it up. Otherwise we
// use the dir and workspace.
if cmd.ProjectName != "" {
projCfg = config.FindProjectByName(cmd.ProjectName)
if projCfg == nil {
return projCtx, fmt.Errorf("no project with name %q configured", cmd.ProjectName)
}
} else {
projCfg = config.FindProject(cmd.Dir, cmd.Workspace)
}
globalCfg = &config
}
if cmd.ProjectName != "" && !hasAtlantisYAML {
return projCtx, fmt.Errorf("cannot specify a project name unless an %s file exists to configure projects", yaml.AtlantisYAMLFilename)
}
projCtx = models.ProjectCommandContext{
BaseRepo: ctx.BaseRepo,
HeadRepo: ctx.HeadRepo,
Pull: ctx.Pull,
User: ctx.User,
Log: ctx.Log,
CommentArgs: cmd.Flags,
Workspace: cmd.Workspace,
RepoRelPath: cmd.Dir,
ProjectName: cmd.ProjectName,
ProjectConfig: projCfg,
GlobalConfig: globalCfg,
}
return projCtx, nil
return p.buildProjectCommandCtx(ctx, cmd, repoDir)
}
func (p *DefaultProjectCommandBuilder) BuildApplyCommand(ctx *CommandContext, cmd *CommentCommand) (models.ProjectCommandContext, error) {
var projCtx models.ProjectCommandContext
unlockFn, err := p.WorkingDirLocker.TryLock(ctx.BaseRepo.FullName, cmd.Workspace, ctx.Pull.Num)
if err != nil {
return projCtx, err
}
defer unlockFn()
repoDir, err := p.WorkingDir.GetWorkingDir(ctx.BaseRepo, ctx.Pull, cmd.Workspace)
if err != nil {
return projCtx, err
}
// todo: can deduplicate this between PlanViaComment
var projCfg *valid.Project
var globalCfg *valid.Spec
return p.buildProjectCommandCtx(ctx, cmd, repoDir)
}
// Parse config file if it exists.
config, err := p.ParserValidator.ReadConfig(repoDir)
if err != nil && !os.IsNotExist(err) {
return projCtx, err
}
hasAtlantisYAML := !os.IsNotExist(err)
if hasAtlantisYAML {
// If they've specified a project by name we look it up. Otherwise we
// use the dir and workspace.
if cmd.ProjectName != "" {
projCfg = config.FindProjectByName(cmd.ProjectName)
if projCfg == nil {
return projCtx, fmt.Errorf("no project with name %q configured", cmd.ProjectName)
}
} else {
projCfg = config.FindProject(cmd.Dir, cmd.Workspace)
}
globalCfg = &config
func (p *DefaultProjectCommandBuilder) buildProjectCommandCtx(ctx *CommandContext, cmd *CommentCommand, repoDir string) (models.ProjectCommandContext, error) {
projCfg, globalCfg, err := p.getCfg(cmd.ProjectName, cmd.Dir, cmd.Workspace, repoDir)
if err != nil {
return models.ProjectCommandContext{}, err
}
if cmd.ProjectName != "" && !hasAtlantisYAML {
return projCtx, fmt.Errorf("cannot specify a project name unless an %s file exists to configure projects", yaml.AtlantisYAMLFilename)
// Override any dir/workspace defined on the comment with what was
// defined in config. This shouldn't matter since we don't allow comments
// with both project name and dir/workspace.
dir := cmd.Dir
workspace := cmd.Workspace
if projCfg != nil {
dir = projCfg.Dir
workspace = projCfg.Workspace
}
projCtx = models.ProjectCommandContext{
return models.ProjectCommandContext{
BaseRepo: ctx.BaseRepo,
HeadRepo: ctx.HeadRepo,
Pull: ctx.Pull,
User: ctx.User,
Log: ctx.Log,
CommentArgs: cmd.Flags,
Workspace: cmd.Workspace,
RepoRelPath: cmd.Dir,
ProjectName: cmd.ProjectName,
Workspace: workspace,
RepoRelPath: dir,
ProjectConfig: projCfg,
GlobalConfig: globalCfg,
RequireApprovalOverride: p.RequireApproval,
}, nil
}
func (p *DefaultProjectCommandBuilder) getCfg(projectName string, dir string, workspace string, repoDir string) (*valid.Project, *valid.Spec, error) {
globalCfg, err := p.ParserValidator.ReadConfig(repoDir)
if err != nil && !os.IsNotExist(err) {
return nil, nil, err
}
return projCtx, nil
hasAtlantisYAML := !os.IsNotExist(err)
if !hasAtlantisYAML && projectName != "" {
return nil, nil, fmt.Errorf("cannot specify a project name unless an %s file exists to configure projects", yaml.AtlantisYAMLFilename)
}
if !hasAtlantisYAML {
return nil, nil, nil
}
// If they've specified a project by name we look it up. Otherwise we
// use the dir and workspace.
if projectName != "" {
projCfg := globalCfg.FindProjectByName(projectName)
if projCfg == nil {
return nil, nil, fmt.Errorf("no project with name %q is defined in %s", projectName, yaml.AtlantisYAMLFilename)
}
return projCfg, &globalCfg, nil
}
projCfgs := globalCfg.FindProjectsByDirWorkspace(dir, workspace)
if len(projCfgs) == 0 {
return nil, nil, nil
}
if len(projCfgs) > 1 {
return nil, nil, fmt.Errorf("must specify project name: more than one project defined in %s matched dir: %q workspace: %q", yaml.AtlantisYAMLFilename, dir, workspace)
}
return &projCfgs[0], &globalCfg, nil
}
// matchingProjects returns the list of projects whose WhenModified fields match

View File

@@ -1,29 +1,458 @@
package events_test
//. "github.com/runatlantis/atlantis/testing"
import (
"io/ioutil"
"path/filepath"
"testing"
//func TestBuildAutoplanCommands(t *testing.T) {
// tmpDir, cleanup := TempDir(t)
// defer cleanup()
//
// workspace := mocks.NewMockWorkingDir()
// vcsClient := vcsmocks.NewMockClientProxy()
//
// builder := &events.DefaultProjectCommandBuilder{
// WorkingDirLocker: events.NewDefaultAtlantisWorkingDirLocker(),
// Workspace: workspace,
// ParserValidator: &yaml.ParserValidator{},
// VCSClient: vcsClient,
// ProjectFinder: &events.DefaultProjectFinder{},
// }
//
// // If autoplan is false, should return empty steps.
// ctxs, err := builder.BuildAutoplanCommands(&events.CommandContext{
// BaseRepo: models.Repo{},
// HeadRepo: models.Repo{},
// Pull: models.PullRequest{},
// User: models.User{},
// Log: nil,
// })
// Ok(t, err)
//}
. "github.com/petergtz/pegomock"
"github.com/runatlantis/atlantis/server/events"
"github.com/runatlantis/atlantis/server/events/mocks"
"github.com/runatlantis/atlantis/server/events/models"
vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks"
"github.com/runatlantis/atlantis/server/events/yaml"
"github.com/runatlantis/atlantis/server/events/yaml/valid"
"github.com/runatlantis/atlantis/server/logging"
. "github.com/runatlantis/atlantis/testing"
)
func TestDefaultProjectCommandBuilder_BuildAutoplanCommands(t *testing.T) {
// exp defines what we will assert on. We don't check all fields in the
// actual contexts.
type exp struct {
projectConfig *valid.Project
dir string
workspace string
}
cases := []struct {
Description string
AtlantisYAML string
exp []exp
}{
{
Description: "no atlantis.yaml",
AtlantisYAML: "",
exp: []exp{
{
projectConfig: nil,
dir: ".",
workspace: "default",
},
},
},
{
Description: "autoplan disabled",
AtlantisYAML: `
version: 2
projects:
- dir: .
autoplan:
enabled: false`,
exp: nil,
},
{
Description: "simple atlantis.yaml",
AtlantisYAML: `
version: 2
projects:
- dir: .
`,
exp: []exp{
{
projectConfig: &valid.Project{
Dir: ".",
Workspace: "default",
Autoplan: valid.Autoplan{
Enabled: true,
WhenModified: []string{"**/*.tf"},
},
},
dir: ".",
workspace: "default",
},
},
},
{
Description: "some projects disabled",
AtlantisYAML: `
version: 2
projects:
- dir: .
autoplan:
enabled: false
- dir: .
workspace: myworkspace
autoplan:
when_modified: ["main.tf"]
- dir: .
workspace: myworkspace2
`,
exp: []exp{
{
projectConfig: &valid.Project{
Dir: ".",
Workspace: "myworkspace",
Autoplan: valid.Autoplan{
Enabled: true,
WhenModified: []string{"main.tf"},
},
},
dir: ".",
workspace: "myworkspace",
},
{
projectConfig: &valid.Project{
Dir: ".",
Workspace: "myworkspace2",
Autoplan: valid.Autoplan{
Enabled: true,
WhenModified: []string{"**/*.tf"},
},
},
dir: ".",
workspace: "myworkspace2",
},
},
},
{
Description: "some projects disabled",
AtlantisYAML: `
version: 2
projects:
- dir: .
autoplan:
enabled: false
- dir: .
workspace: myworkspace
autoplan:
when_modified: ["main.tf"]
- dir: .
workspace: myworkspace2
`,
exp: []exp{
{
projectConfig: &valid.Project{
Dir: ".",
Workspace: "myworkspace",
Autoplan: valid.Autoplan{
Enabled: true,
WhenModified: []string{"main.tf"},
},
},
dir: ".",
workspace: "myworkspace",
},
{
projectConfig: &valid.Project{
Dir: ".",
Workspace: "myworkspace2",
Autoplan: valid.Autoplan{
Enabled: true,
WhenModified: []string{"**/*.tf"},
},
},
dir: ".",
workspace: "myworkspace2",
},
},
},
{
Description: "no projects modified",
AtlantisYAML: `
version: 2
projects:
- dir: mydir
`,
exp: nil,
},
}
for _, c := range cases {
t.Run(c.Description, func(t *testing.T) {
RegisterMockTestingT(t)
tmpDir, cleanup := TempDir(t)
defer cleanup()
baseRepo := models.Repo{}
headRepo := models.Repo{}
pull := models.PullRequest{}
logger := logging.NewNoopLogger()
workingDir := mocks.NewMockWorkingDir()
When(workingDir.Clone(logger, baseRepo, headRepo, pull, "default")).ThenReturn(tmpDir, nil)
if c.AtlantisYAML != "" {
err := ioutil.WriteFile(filepath.Join(tmpDir, yaml.AtlantisYAMLFilename), []byte(c.AtlantisYAML), 0600)
Ok(t, err)
}
err := ioutil.WriteFile(filepath.Join(tmpDir, "main.tf"), nil, 0600)
Ok(t, err)
vcsClient := vcsmocks.NewMockClientProxy()
When(vcsClient.GetModifiedFiles(baseRepo, pull)).ThenReturn([]string{"main.tf"}, nil)
builder := &events.DefaultProjectCommandBuilder{
WorkingDirLocker: events.NewDefaultAtlantisWorkingDirLocker(),
WorkingDir: workingDir,
ParserValidator: &yaml.ParserValidator{},
VCSClient: vcsClient,
ProjectFinder: &events.DefaultProjectFinder{},
}
ctxs, err := builder.BuildAutoplanCommands(&events.CommandContext{
BaseRepo: baseRepo,
HeadRepo: headRepo,
Pull: pull,
User: models.User{},
Log: logger,
})
Ok(t, err)
Equals(t, len(c.exp), len(ctxs))
for i, actCtx := range ctxs {
expCtx := c.exp[i]
Equals(t, baseRepo, actCtx.BaseRepo)
Equals(t, baseRepo, actCtx.HeadRepo)
Equals(t, pull, actCtx.Pull)
Equals(t, models.User{}, actCtx.User)
Equals(t, logger, actCtx.Log)
Equals(t, 0, len(actCtx.CommentArgs))
Equals(t, false, actCtx.RequireApprovalOverride)
Equals(t, expCtx.projectConfig, actCtx.ProjectConfig)
Equals(t, expCtx.dir, actCtx.RepoRelPath)
Equals(t, expCtx.workspace, actCtx.Workspace)
}
})
}
}
func TestDefaultProjectCommandBuilder_BuildPlanApplyCommand(t *testing.T) {
cases := []struct {
Description string
AtlantisYAML string
Cmd events.CommentCommand
ExpProjectConfig *valid.Project
ExpCommentArgs []string
ExpWorkspace string
ExpDir string
ExpErr string
}{
{
Description: "no atlantis.yaml",
Cmd: events.CommentCommand{
Dir: ".",
Flags: []string{"commentarg"},
Name: events.Plan,
Workspace: "myworkspace",
},
AtlantisYAML: "",
ExpProjectConfig: nil,
ExpCommentArgs: []string{"commentarg"},
ExpWorkspace: "myworkspace",
ExpDir: ".",
},
{
Description: "no atlantis.yaml with project flag",
Cmd: events.CommentCommand{
Dir: ".",
Name: events.Plan,
ProjectName: "myproject",
},
AtlantisYAML: "",
ExpErr: "cannot specify a project name unless an atlantis.yaml file exists to configure projects",
},
{
Description: "simple atlantis.yaml",
Cmd: events.CommentCommand{
Dir: ".",
Name: events.Plan,
Workspace: "myworkspace",
},
AtlantisYAML: `
version: 2
projects:
- dir: .
workspace: myworkspace
apply_requirements: [approved]`,
ExpProjectConfig: &valid.Project{
Dir: ".",
Workspace: "myworkspace",
Autoplan: valid.Autoplan{
WhenModified: []string{"**/*.tf"},
Enabled: true,
},
ApplyRequirements: []string{"approved"},
},
ExpWorkspace: "myworkspace",
ExpDir: ".",
},
{
Description: "atlantis.yaml wrong dir",
Cmd: events.CommentCommand{
Dir: ".",
Name: events.Plan,
Workspace: "myworkspace",
},
AtlantisYAML: `
version: 2
projects:
- dir: notroot
workspace: myworkspace
apply_requirements: [approved]`,
ExpProjectConfig: nil,
ExpWorkspace: "myworkspace",
ExpDir: ".",
},
{
Description: "atlantis.yaml wrong workspace",
Cmd: events.CommentCommand{
Dir: ".",
Name: events.Plan,
Workspace: "myworkspace",
},
AtlantisYAML: `
version: 2
projects:
- dir: .
workspace: notmyworkspace
apply_requirements: [approved]`,
ExpProjectConfig: nil,
ExpWorkspace: "myworkspace",
ExpDir: ".",
},
{
Description: "atlantis.yaml with projectname",
Cmd: events.CommentCommand{
Name: events.Plan,
ProjectName: "myproject",
},
AtlantisYAML: `
version: 2
projects:
- name: myproject
dir: .
workspace: myworkspace
apply_requirements: [approved]`,
ExpProjectConfig: &valid.Project{
Dir: ".",
Workspace: "myworkspace",
Autoplan: valid.Autoplan{
WhenModified: []string{"**/*.tf"},
Enabled: true,
},
ApplyRequirements: []string{"approved"},
Name: String("myproject"),
},
ExpWorkspace: "myworkspace",
ExpDir: ".",
},
{
Description: "atlantis.yaml with multiple dir/workspaces matching",
Cmd: events.CommentCommand{
Name: events.Plan,
Dir: ".",
Workspace: "myworkspace",
},
AtlantisYAML: `
version: 2
projects:
- name: myproject
dir: .
workspace: myworkspace
apply_requirements: [approved]
- name: myproject2
dir: .
workspace: myworkspace
`,
ExpErr: "must specify project name: more than one project defined in atlantis.yaml matched dir: \".\" workspace: \"myworkspace\"",
},
{
Description: "atlantis.yaml with project flag not matching",
Cmd: events.CommentCommand{
Name: events.Plan,
Dir: ".",
Workspace: "default",
ProjectName: "notconfigured",
},
AtlantisYAML: `
version: 2
projects:
- dir: .
`,
ExpErr: "no project with name \"notconfigured\" is defined in atlantis.yaml",
},
}
for _, c := range cases {
// NOTE: we're testing both plan and apply here.
for _, cmdName := range []events.CommandName{events.Plan, events.Apply} {
t.Run(c.Description, func(t *testing.T) {
RegisterMockTestingT(t)
tmpDir, cleanup := TempDir(t)
defer cleanup()
baseRepo := models.Repo{}
headRepo := models.Repo{}
pull := models.PullRequest{}
logger := logging.NewNoopLogger()
workingDir := mocks.NewMockWorkingDir()
if cmdName == events.Plan {
When(workingDir.Clone(logger, baseRepo, headRepo, pull, c.Cmd.Workspace)).ThenReturn(tmpDir, nil)
} else {
When(workingDir.GetWorkingDir(baseRepo, pull, c.Cmd.Workspace)).ThenReturn(tmpDir, nil)
}
if c.AtlantisYAML != "" {
err := ioutil.WriteFile(filepath.Join(tmpDir, yaml.AtlantisYAMLFilename), []byte(c.AtlantisYAML), 0600)
Ok(t, err)
}
err := ioutil.WriteFile(filepath.Join(tmpDir, "main.tf"), nil, 0600)
Ok(t, err)
vcsClient := vcsmocks.NewMockClientProxy()
When(vcsClient.GetModifiedFiles(baseRepo, pull)).ThenReturn([]string{"main.tf"}, nil)
builder := &events.DefaultProjectCommandBuilder{
WorkingDirLocker: events.NewDefaultAtlantisWorkingDirLocker(),
WorkingDir: workingDir,
ParserValidator: &yaml.ParserValidator{},
VCSClient: vcsClient,
ProjectFinder: &events.DefaultProjectFinder{},
}
cmdCtx := &events.CommandContext{
BaseRepo: baseRepo,
HeadRepo: headRepo,
Pull: pull,
User: models.User{},
Log: logger,
}
var actCtx models.ProjectCommandContext
if cmdName == events.Plan {
actCtx, err = builder.BuildPlanCommand(cmdCtx, &c.Cmd)
} else {
actCtx, err = builder.BuildApplyCommand(cmdCtx, &c.Cmd)
}
if c.ExpErr != "" {
ErrEquals(t, c.ExpErr, err)
return
}
Ok(t, err)
Equals(t, baseRepo, actCtx.BaseRepo)
Equals(t, baseRepo, actCtx.HeadRepo)
Equals(t, pull, actCtx.Pull)
Equals(t, models.User{}, actCtx.User)
Equals(t, logger, actCtx.Log)
Equals(t, false, actCtx.RequireApprovalOverride)
Equals(t, c.ExpProjectConfig, actCtx.ProjectConfig)
Equals(t, c.ExpDir, actCtx.RepoRelPath)
Equals(t, c.ExpWorkspace, actCtx.Workspace)
Equals(t, c.ExpCommentArgs, actCtx.CommentArgs)
})
}
}
}
func String(v string) *string { return &v }

View File

@@ -17,8 +17,8 @@ type ApplyStepRunner struct {
func (a *ApplyStepRunner) Run(ctx models.ProjectCommandContext, extraArgs []string, path string) (string, error) {
// todo: move this to a common library
planFileName := fmt.Sprintf("%s.tfplan", ctx.Workspace)
if ctx.ProjectName != "" {
planFileName = fmt.Sprintf("%s-%s", ctx.ProjectName, planFileName)
if ctx.ProjectConfig != nil && ctx.ProjectConfig.Name != nil {
planFileName = fmt.Sprintf("%s-%s", *ctx.ProjectConfig.Name, planFileName)
}
planFile := filepath.Join(path, planFileName)
stat, err := os.Stat(planFile)

View File

@@ -81,10 +81,13 @@ func TestRun_AppliesCorrectProjectPlan(t *testing.T) {
When(terraform.RunCommandWithVersion(matchers.AnyPtrToLoggingSimpleLogger(), AnyString(), AnyStringSlice(), matchers2.AnyPtrToGoVersionVersion(), AnyString())).
ThenReturn("output", nil)
projectName := "projectname"
output, err := o.Run(models.ProjectCommandContext{
Workspace: "default",
RepoRelPath: ".",
ProjectName: "projectname",
ProjectConfig: &valid.Project{
Name: &projectName,
},
CommentArgs: []string{"comment", "args"},
}, []string{"extra", "args"}, tmpDir)
Ok(t, err)

View File

@@ -34,8 +34,8 @@ func (p *PlanStepRunner) Run(ctx models.ProjectCommandContext, extraArgs []strin
// todo: move this to a common library
planFileName := fmt.Sprintf("%s.tfplan", ctx.Workspace)
if ctx.ProjectName != "" {
planFileName = fmt.Sprintf("%s-%s", ctx.ProjectName, planFileName)
if ctx.ProjectConfig != nil && ctx.ProjectConfig.Name != nil {
planFileName = fmt.Sprintf("%s-%s", *ctx.ProjectConfig.Name, planFileName)
}
planFile := filepath.Join(path, planFileName)
userVar := fmt.Sprintf("%s=%s", atlantisUserTFVar, ctx.User.Username)

View File

@@ -14,6 +14,7 @@ import (
matchers2 "github.com/runatlantis/atlantis/server/events/run/mocks/matchers"
"github.com/runatlantis/atlantis/server/events/runtime"
"github.com/runatlantis/atlantis/server/events/terraform/mocks"
"github.com/runatlantis/atlantis/server/events/yaml/valid"
"github.com/runatlantis/atlantis/server/logging"
. "github.com/runatlantis/atlantis/testing"
)
@@ -282,13 +283,16 @@ func TestRun_UsesDiffPathForProject(t *testing.T) {
expPlanArgs := []string{"plan", "-refresh", "-no-color", "-out", "/path/projectname-default.tfplan", "-var", "atlantis_user=username", "extra", "args", "comment", "args"}
When(terraform.RunCommandWithVersion(logger, "/path", expPlanArgs, tfVersion, "default")).ThenReturn("output", nil)
projectName := "projectname"
output, err := s.Run(models.ProjectCommandContext{
Log: logger,
Workspace: "default",
RepoRelPath: ".",
ProjectName: "projectname",
User: models.User{Username: "username"},
CommentArgs: []string{"comment", "args"},
ProjectConfig: &valid.Project{
Name: &projectName,
},
}, []string{"extra", "args"}, "/path")
Ok(t, err)
Equals(t, "output", output)

View File

@@ -31,13 +31,14 @@ func (s Spec) GetApplyStage(workflowName string) *Stage {
return nil
}
func (s Spec) FindProject(dir string, workspace string) *Project {
func (s Spec) FindProjectsByDirWorkspace(dir string, workspace string) []Project {
var ps []Project
for _, p := range s.Projects {
if p.Dir == dir && p.Workspace == workspace {
return &p
ps = append(ps, p)
}
}
return nil
return ps
}
func (s Spec) FindProjectByName(name string) *Project {