mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-29 21:38:00 +00:00
Signed-off-by: Andrew Carter <andrew@emailcarter.com> Signed-off-by: Luke Massa <lukefrederickmassa@gmail.com> Co-authored-by: Finn Arne Gangstad <finnag@gmail.com> Co-authored-by: Rui Chen <rui@chenrui.dev> Co-authored-by: PePe Amengual <2208324+jamengual@users.noreply.github.com> Co-authored-by: Luke Massa <lukefrederickmassa@gmail.com>
162 lines
5.4 KiB
Go
162 lines
5.4 KiB
Go
package events
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/runatlantis/atlantis/server/core/config/valid"
|
|
"github.com/runatlantis/atlantis/server/core/runtime"
|
|
"github.com/runatlantis/atlantis/server/events/command"
|
|
"github.com/runatlantis/atlantis/server/events/models"
|
|
"github.com/runatlantis/atlantis/server/events/vcs"
|
|
)
|
|
|
|
//go:generate pegomock generate --package mocks -o mocks/mock_pre_workflow_hook_url_generator.go PreWorkflowHookURLGenerator
|
|
|
|
// PreWorkflowHookURLGenerator generates urls to view the pre workflow progress.
|
|
type PreWorkflowHookURLGenerator interface {
|
|
GenerateProjectWorkflowHookURL(hookID string) (string, error)
|
|
}
|
|
|
|
//go:generate pegomock generate --package mocks -o mocks/mock_pre_workflows_hooks_command_runner.go PreWorkflowHooksCommandRunner
|
|
|
|
type PreWorkflowHooksCommandRunner interface {
|
|
RunPreHooks(ctx *command.Context, cmd *CommentCommand) error
|
|
}
|
|
|
|
// DefaultPreWorkflowHooksCommandRunner is the first step when processing a workflow hook commands.
|
|
type DefaultPreWorkflowHooksCommandRunner struct {
|
|
VCSClient vcs.Client `validate:"required"`
|
|
WorkingDirLocker WorkingDirLocker `validate:"required"`
|
|
WorkingDir WorkingDir `validate:"required"`
|
|
GlobalCfg valid.GlobalCfg `validate:"required"`
|
|
PreWorkflowHookRunner runtime.PreWorkflowHookRunner `validate:"required"`
|
|
CommitStatusUpdater CommitStatusUpdater `validate:"required"`
|
|
Router PreWorkflowHookURLGenerator `validate:"required"`
|
|
}
|
|
|
|
// RunPreHooks runs pre_workflow_hooks when PR is opened or updated.
|
|
func (w *DefaultPreWorkflowHooksCommandRunner) RunPreHooks(ctx *command.Context, cmd *CommentCommand) error {
|
|
preWorkflowHooks := make([]*valid.WorkflowHook, 0)
|
|
for _, repo := range w.GlobalCfg.Repos {
|
|
if repo.IDMatches(ctx.Pull.BaseRepo.ID()) && len(repo.PreWorkflowHooks) > 0 {
|
|
preWorkflowHooks = append(preWorkflowHooks, repo.PreWorkflowHooks...)
|
|
}
|
|
}
|
|
|
|
// short circuit any other calls if there are no pre-hooks configured
|
|
if len(preWorkflowHooks) == 0 {
|
|
return nil
|
|
}
|
|
|
|
ctx.Log.Info("Pre-workflow hooks configured, running...")
|
|
|
|
unlockFn, err := w.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, DefaultWorkspace, DefaultRepoRelDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ctx.Log.Debug("got workspace lock")
|
|
defer unlockFn()
|
|
|
|
repoDir, err := w.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, DefaultWorkspace)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var escapedArgs []string
|
|
if cmd != nil {
|
|
escapedArgs = escapeArgs(cmd.Flags)
|
|
}
|
|
|
|
err = w.runHooks(
|
|
models.WorkflowHookCommandContext{
|
|
BaseRepo: ctx.Pull.BaseRepo,
|
|
HeadRepo: ctx.HeadRepo,
|
|
Log: ctx.Log,
|
|
Pull: ctx.Pull,
|
|
User: ctx.User,
|
|
Verbose: false,
|
|
EscapedCommentArgs: escapedArgs,
|
|
CommandName: cmd.Name.String(),
|
|
API: ctx.API,
|
|
},
|
|
preWorkflowHooks, repoDir)
|
|
|
|
if err != nil {
|
|
ctx.Log.Err("Error running pre-workflow hooks %s.", err)
|
|
return err
|
|
}
|
|
|
|
ctx.Log.Info("Pre-workflow hooks completed successfully")
|
|
|
|
return nil
|
|
}
|
|
|
|
func (w *DefaultPreWorkflowHooksCommandRunner) runHooks(
|
|
ctx models.WorkflowHookCommandContext,
|
|
preWorkflowHooks []*valid.WorkflowHook,
|
|
repoDir string,
|
|
) error {
|
|
for i, hook := range preWorkflowHooks {
|
|
ctx.HookDescription = hook.StepDescription
|
|
if ctx.HookDescription == "" {
|
|
ctx.HookDescription = fmt.Sprintf("Pre workflow hook #%d", i)
|
|
}
|
|
|
|
ctx.HookStepName = fmt.Sprintf("pre %s #%d", ctx.CommandName, i)
|
|
|
|
ctx.Log.Debug("Processing pre workflow hook '%s', Command '%s', Target commands [%s]",
|
|
ctx.HookDescription, ctx.CommandName, hook.Commands)
|
|
if hook.Commands != "" && !strings.Contains(hook.Commands, ctx.CommandName) {
|
|
ctx.Log.Debug("Skipping pre workflow hook '%s' as command '%s' is not in Commands [%s]",
|
|
ctx.HookDescription, ctx.CommandName, hook.Commands)
|
|
continue
|
|
}
|
|
|
|
ctx.Log.Debug("Running pre workflow hook: '%s'", ctx.HookDescription)
|
|
ctx.HookID = uuid.NewString()
|
|
shell := hook.Shell
|
|
if shell == "" {
|
|
ctx.Log.Debug("Setting shell to default: '%s'", shell)
|
|
shell = "sh"
|
|
}
|
|
shellArgs := hook.ShellArgs
|
|
if shellArgs == "" {
|
|
ctx.Log.Debug("Setting shellArgs to default: '%s'", shellArgs)
|
|
shellArgs = "-c"
|
|
}
|
|
url, err := w.Router.GenerateProjectWorkflowHookURL(ctx.HookID)
|
|
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)
|
|
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)
|
|
|
|
if err != nil {
|
|
if err := w.CommitStatusUpdater.UpdatePreWorkflowHook(ctx.Log, ctx.Pull, models.FailedCommitStatus, ctx.HookDescription, runtimeDesc, url); err != nil {
|
|
ctx.Log.Warn("unable to update pre workflow hook status: %s", err)
|
|
}
|
|
return err
|
|
}
|
|
|
|
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)
|
|
if !ctx.API {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|