mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-28 22:28:25 +00:00
feat: make api plan apply support workflow hooks (#4482)
Co-authored-by: PePe Amengual <jose.amengual@gmail.com>
This commit is contained in:
@@ -20,16 +20,19 @@ import (
|
||||
const atlantisTokenHeader = "X-Atlantis-Token"
|
||||
|
||||
type APIController struct {
|
||||
APISecret []byte
|
||||
Locker locking.Locker
|
||||
Logger logging.SimpleLogging
|
||||
Parser events.EventParsing
|
||||
ProjectCommandBuilder events.ProjectCommandBuilder
|
||||
ProjectPlanCommandRunner events.ProjectPlanCommandRunner
|
||||
ProjectApplyCommandRunner events.ProjectApplyCommandRunner
|
||||
RepoAllowlistChecker *events.RepoAllowlistChecker
|
||||
Scope tally.Scope
|
||||
VCSClient vcs.Client
|
||||
APISecret []byte
|
||||
Locker locking.Locker
|
||||
Logger logging.SimpleLogging
|
||||
Parser events.EventParsing
|
||||
ProjectCommandBuilder events.ProjectCommandBuilder
|
||||
ProjectPlanCommandRunner events.ProjectPlanCommandRunner
|
||||
ProjectApplyCommandRunner events.ProjectApplyCommandRunner
|
||||
FailOnPreWorkflowHookError bool
|
||||
PreWorkflowHooksCommandRunner events.PreWorkflowHooksCommandRunner
|
||||
PostWorkflowHooksCommandRunner events.PostWorkflowHooksCommandRunner
|
||||
RepoAllowlistChecker *events.RepoAllowlistChecker
|
||||
Scope tally.Scope
|
||||
VCSClient vcs.Client
|
||||
}
|
||||
|
||||
type APIRequest struct {
|
||||
@@ -44,7 +47,7 @@ type APIRequest struct {
|
||||
}
|
||||
}
|
||||
|
||||
func (a *APIRequest) getCommands(ctx *command.Context, cmdBuilder func(*command.Context, *events.CommentCommand) ([]command.ProjectContext, error)) ([]command.ProjectContext, error) {
|
||||
func (a *APIRequest) getCommands(ctx *command.Context, cmdBuilder func(*command.Context, *events.CommentCommand) ([]command.ProjectContext, error)) ([]command.ProjectContext, []*events.CommentCommand, error) {
|
||||
cc := make([]*events.CommentCommand, 0)
|
||||
|
||||
for _, project := range a.Projects {
|
||||
@@ -63,12 +66,12 @@ func (a *APIRequest) getCommands(ctx *command.Context, cmdBuilder func(*command.
|
||||
for _, commentCommand := range cc {
|
||||
projectCmds, err := cmdBuilder(ctx, commentCommand)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build command: %v", err)
|
||||
return nil, nil, fmt.Errorf("failed to build command: %v", err)
|
||||
}
|
||||
cmds = append(cmds, projectCmds...)
|
||||
}
|
||||
|
||||
return cmds, nil
|
||||
return cmds, cc, nil
|
||||
}
|
||||
|
||||
func (a *APIController) apiReportError(w http.ResponseWriter, code int, err error) {
|
||||
@@ -142,29 +145,55 @@ func (a *APIController) Apply(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (a *APIController) apiPlan(request *APIRequest, ctx *command.Context) (*command.Result, error) {
|
||||
cmds, err := request.getCommands(ctx, a.ProjectCommandBuilder.BuildPlanCommands)
|
||||
cmds, cc, err := request.getCommands(ctx, a.ProjectCommandBuilder.BuildPlanCommands)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var projectResults []command.ProjectResult
|
||||
for _, cmd := range cmds {
|
||||
for i, cmd := range cmds {
|
||||
err = a.PreWorkflowHooksCommandRunner.RunPreHooks(ctx, cc[i])
|
||||
if err != nil {
|
||||
ctx.Log.Err("Error running pre-workflow hooks %s.", err)
|
||||
if a.FailOnPreWorkflowHookError {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
res := a.ProjectPlanCommandRunner.Plan(cmd)
|
||||
projectResults = append(projectResults, res)
|
||||
|
||||
err = a.PostWorkflowHooksCommandRunner.RunPostHooks(ctx, cc[i])
|
||||
if err != nil {
|
||||
ctx.Log.Err("Error running post-workflow hooks %s.", err)
|
||||
}
|
||||
}
|
||||
return &command.Result{ProjectResults: projectResults}, nil
|
||||
}
|
||||
|
||||
func (a *APIController) apiApply(request *APIRequest, ctx *command.Context) (*command.Result, error) {
|
||||
cmds, err := request.getCommands(ctx, a.ProjectCommandBuilder.BuildApplyCommands)
|
||||
cmds, cc, err := request.getCommands(ctx, a.ProjectCommandBuilder.BuildApplyCommands)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var projectResults []command.ProjectResult
|
||||
for _, cmd := range cmds {
|
||||
for i, cmd := range cmds {
|
||||
err = a.PreWorkflowHooksCommandRunner.RunPreHooks(ctx, cc[i])
|
||||
if err != nil {
|
||||
ctx.Log.Err("Error running pre-workflow hooks %s.", err)
|
||||
if a.FailOnPreWorkflowHookError {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
res := a.ProjectApplyCommandRunner.Apply(cmd)
|
||||
projectResults = append(projectResults, res)
|
||||
|
||||
err = a.PostWorkflowHooksCommandRunner.RunPostHooks(ctx, cc[i])
|
||||
if err != nil {
|
||||
ctx.Log.Err("Error running post-workflow hooks %s.", err)
|
||||
}
|
||||
}
|
||||
return &command.Result{ProjectResults: projectResults}, nil
|
||||
}
|
||||
@@ -223,6 +252,7 @@ func (a *APIController) apiParseAndValidate(r *http.Request) (*APIRequest, *comm
|
||||
},
|
||||
Scope: a.Scope,
|
||||
Log: a.Logger,
|
||||
API: true,
|
||||
}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -86,17 +86,27 @@ func setup(t *testing.T) (controllers.APIController, *MockProjectCommandBuilder,
|
||||
ApplySuccess: "success",
|
||||
})
|
||||
|
||||
preWorkflowHooksCommandRunner := NewMockPreWorkflowHooksCommandRunner()
|
||||
|
||||
When(preWorkflowHooksCommandRunner.RunPreHooks(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn(nil)
|
||||
|
||||
postWorkflowHooksCommandRunner := NewMockPostWorkflowHooksCommandRunner()
|
||||
|
||||
When(postWorkflowHooksCommandRunner.RunPostHooks(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn(nil)
|
||||
|
||||
ac := controllers.APIController{
|
||||
APISecret: []byte(atlantisToken),
|
||||
Locker: locker,
|
||||
Logger: logger,
|
||||
Scope: scope,
|
||||
Parser: parser,
|
||||
ProjectCommandBuilder: projectCommandBuilder,
|
||||
ProjectPlanCommandRunner: projectCommandRunner,
|
||||
ProjectApplyCommandRunner: projectCommandRunner,
|
||||
VCSClient: vcsClient,
|
||||
RepoAllowlistChecker: repoAllowlistChecker,
|
||||
APISecret: []byte(atlantisToken),
|
||||
Locker: locker,
|
||||
Logger: logger,
|
||||
Scope: scope,
|
||||
Parser: parser,
|
||||
ProjectCommandBuilder: projectCommandBuilder,
|
||||
ProjectPlanCommandRunner: projectCommandRunner,
|
||||
ProjectApplyCommandRunner: projectCommandRunner,
|
||||
PreWorkflowHooksCommandRunner: preWorkflowHooksCommandRunner,
|
||||
PostWorkflowHooksCommandRunner: postWorkflowHooksCommandRunner,
|
||||
VCSClient: vcsClient,
|
||||
RepoAllowlistChecker: repoAllowlistChecker,
|
||||
}
|
||||
return ac, projectCommandBuilder, projectCommandRunner
|
||||
}
|
||||
|
||||
@@ -43,4 +43,7 @@ type Context struct {
|
||||
ClearPolicyApproval bool
|
||||
|
||||
Trigger Trigger
|
||||
|
||||
// API is true if plan/apply by API endpoints
|
||||
API bool
|
||||
}
|
||||
|
||||
@@ -653,6 +653,8 @@ type WorkflowHookCommandContext struct {
|
||||
// Workspace is the Terraform workspace this project is in. It will always
|
||||
// be set.
|
||||
Workspace string
|
||||
// API is true if plan/apply by API endpoints
|
||||
API bool
|
||||
}
|
||||
|
||||
// PlanSuccessStats holds stats for a plan.
|
||||
|
||||
@@ -79,6 +79,7 @@ func (w *DefaultPostWorkflowHooksCommandRunner) RunPostHooks(ctx *command.Contex
|
||||
Verbose: false,
|
||||
EscapedCommentArgs: escapedArgs,
|
||||
CommandName: cmd.Name.String(),
|
||||
API: ctx.API,
|
||||
},
|
||||
postWorkflowHooks, repoDir)
|
||||
|
||||
@@ -124,7 +125,7 @@ func (w *DefaultPostWorkflowHooksCommandRunner) runHooks(
|
||||
shellArgs = "-c"
|
||||
}
|
||||
url, err := w.Router.GenerateProjectWorkflowHookURL(ctx.HookID)
|
||||
if err != nil {
|
||||
if err != nil && !ctx.API {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ func (w *DefaultPreWorkflowHooksCommandRunner) RunPreHooks(ctx *command.Context,
|
||||
Verbose: false,
|
||||
EscapedCommentArgs: escapedArgs,
|
||||
CommandName: cmd.Name.String(),
|
||||
API: ctx.API,
|
||||
},
|
||||
preWorkflowHooks, repoDir)
|
||||
|
||||
@@ -135,13 +136,17 @@ func (w *DefaultPreWorkflowHooksCommandRunner) runHooks(
|
||||
shellArgs = "-c"
|
||||
}
|
||||
url, err := w.Router.GenerateProjectWorkflowHookURL(ctx.HookID)
|
||||
if err != nil {
|
||||
if err != nil && !ctx.API {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := w.CommitStatusUpdater.UpdatePreWorkflowHook(ctx.Log, ctx.Pull, models.PendingCommitStatus, ctx.HookDescription, "", url); err != nil {
|
||||
ctx.Log.Warn("unable to update pre workflow hook status: %s", err)
|
||||
return err
|
||||
ctx.Log.Info("is api? %v", ctx.API)
|
||||
if !ctx.API {
|
||||
ctx.Log.Info("is api? %v", ctx.API)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, runtimeDesc, err := w.PreWorkflowHookRunner.Run(ctx, hook.RunCommand, shell, shellArgs, repoDir)
|
||||
@@ -155,7 +160,9 @@ func (w *DefaultPreWorkflowHooksCommandRunner) runHooks(
|
||||
|
||||
if err := w.CommitStatusUpdater.UpdatePreWorkflowHook(ctx.Log, ctx.Pull, models.SuccessCommitStatus, ctx.HookDescription, runtimeDesc, url); err != nil {
|
||||
ctx.Log.Warn("unable to update pre workflow hook status: %s", err)
|
||||
return err
|
||||
if !ctx.API {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -876,16 +876,19 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
|
||||
StatsScope: statsScope.SubScope("api"),
|
||||
}
|
||||
apiController := &controllers.APIController{
|
||||
APISecret: []byte(userConfig.APISecret),
|
||||
Locker: lockingClient,
|
||||
Logger: logger,
|
||||
Parser: eventParser,
|
||||
ProjectCommandBuilder: projectCommandBuilder,
|
||||
ProjectPlanCommandRunner: instrumentedProjectCmdRunner,
|
||||
ProjectApplyCommandRunner: instrumentedProjectCmdRunner,
|
||||
RepoAllowlistChecker: repoAllowlist,
|
||||
Scope: statsScope.SubScope("api"),
|
||||
VCSClient: vcsClient,
|
||||
APISecret: []byte(userConfig.APISecret),
|
||||
Locker: lockingClient,
|
||||
Logger: logger,
|
||||
Parser: eventParser,
|
||||
ProjectCommandBuilder: projectCommandBuilder,
|
||||
ProjectPlanCommandRunner: instrumentedProjectCmdRunner,
|
||||
ProjectApplyCommandRunner: instrumentedProjectCmdRunner,
|
||||
FailOnPreWorkflowHookError: userConfig.FailOnPreWorkflowHookError,
|
||||
PreWorkflowHooksCommandRunner: preWorkflowHooksCommandRunner,
|
||||
PostWorkflowHooksCommandRunner: postWorkflowHooksCommandRunner,
|
||||
RepoAllowlistChecker: repoAllowlist,
|
||||
Scope: statsScope.SubScope("api"),
|
||||
VCSClient: vcsClient,
|
||||
}
|
||||
|
||||
eventsController := &events_controllers.VCSEventsController{
|
||||
|
||||
Reference in New Issue
Block a user