mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-08-05 05:18:33 +00:00
Test BuildAutoplanCommands
This commit is contained in:
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 == "/" {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -237,6 +237,5 @@ type ProjectCommandContext struct {
|
||||
// ex. atlantis plan -- -target=resource
|
||||
CommentArgs []string
|
||||
Workspace string
|
||||
ProjectName string
|
||||
RequireApprovalOverride bool
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user