mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-29 18:28:22 +00:00
114 lines
3.7 KiB
Go
114 lines
3.7 KiB
Go
package events
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hootsuite/atlantis/server/events/github"
|
|
"github.com/hootsuite/atlantis/server/logging"
|
|
"github.com/hootsuite/atlantis/server/recovery"
|
|
)
|
|
|
|
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_command_runner.go CommandRunner
|
|
|
|
type CommandRunner interface {
|
|
ExecuteCommand(ctx *CommandContext)
|
|
}
|
|
|
|
// CommandHandler is the first step when processing a comment command.
|
|
type CommandHandler struct {
|
|
PlanExecutor Executor
|
|
ApplyExecutor Executor
|
|
HelpExecutor Executor
|
|
LockURLGenerator LockURLGenerator
|
|
GHClient github.Client
|
|
GHStatus GHStatusUpdater
|
|
EventParser EventParsing
|
|
EnvLocker EnvLocker
|
|
GHCommentRenderer *GithubCommentRenderer
|
|
Logger *logging.SimpleLogger
|
|
}
|
|
|
|
func (c *CommandHandler) ExecuteCommand(ctx *CommandContext) {
|
|
// Set up logger specific to this command.
|
|
// It's safe to reuse the underlying logger.
|
|
src := fmt.Sprintf("%s/pull/%d", ctx.BaseRepo.FullName, ctx.Pull.Num)
|
|
ctx.Log = logging.NewSimpleLogger(src, c.Logger.Logger, true, c.Logger.Level)
|
|
defer c.logPanics(ctx)
|
|
|
|
// Get additional data from the pull request.
|
|
ghPull, _, err := c.GHClient.GetPullRequest(ctx.BaseRepo, ctx.Pull.Num)
|
|
if err != nil {
|
|
ctx.Log.Err("making pull request API call to GitHub: %s", err)
|
|
return
|
|
}
|
|
if ghPull.GetState() != "open" {
|
|
ctx.Log.Info("command was run on closed pull request")
|
|
c.GHClient.CreateComment(ctx.BaseRepo, ctx.Pull, "Atlantis commands can't be run on closed pull requests") // nolint: errcheck
|
|
return
|
|
}
|
|
pull, headRepo, err := c.EventParser.ExtractPullData(ghPull)
|
|
if err != nil {
|
|
ctx.Log.Err("extracting required fields from comment data: %s", err)
|
|
return
|
|
}
|
|
ctx.Pull = pull
|
|
ctx.HeadRepo = headRepo
|
|
c.run(ctx)
|
|
}
|
|
|
|
func (c *CommandHandler) SetLockURL(f func(id string) (url string)) {
|
|
c.LockURLGenerator.SetLockURL(f)
|
|
}
|
|
|
|
func (c *CommandHandler) run(ctx *CommandContext) {
|
|
c.GHStatus.Update(ctx.BaseRepo, ctx.Pull, Pending, ctx.Command) // nolint: errcheck
|
|
if !c.EnvLocker.TryLock(ctx.BaseRepo.FullName, ctx.Command.Environment, ctx.Pull.Num) {
|
|
errMsg := fmt.Sprintf(
|
|
"The %s environment is currently locked by another"+
|
|
" command that is running for this pull request."+
|
|
" Wait until the previous command is complete and try again.",
|
|
ctx.Command.Environment)
|
|
ctx.Log.Warn(errMsg)
|
|
c.updatePull(ctx, CommandResponse{Failure: errMsg})
|
|
return
|
|
}
|
|
defer c.EnvLocker.Unlock(ctx.BaseRepo.FullName, ctx.Command.Environment, ctx.Pull.Num)
|
|
|
|
var cr CommandResponse
|
|
switch ctx.Command.Name {
|
|
case Plan:
|
|
cr = c.PlanExecutor.Execute(ctx)
|
|
case Apply:
|
|
cr = c.ApplyExecutor.Execute(ctx)
|
|
case Help:
|
|
cr = c.HelpExecutor.Execute(ctx)
|
|
default:
|
|
ctx.Log.Err("failed to determine desired command, neither plan nor apply")
|
|
}
|
|
c.updatePull(ctx, cr)
|
|
}
|
|
|
|
func (c *CommandHandler) updatePull(ctx *CommandContext, res CommandResponse) {
|
|
// Log if we got any errors or failures.
|
|
if res.Error != nil {
|
|
ctx.Log.Err(res.Error.Error())
|
|
} else if res.Failure != "" {
|
|
ctx.Log.Warn(res.Failure)
|
|
}
|
|
|
|
// Update the pull request's status icon and comment back.
|
|
c.GHStatus.UpdateProjectResult(ctx, res) // nolint: errcheck
|
|
comment := c.GHCommentRenderer.Render(res, ctx.Command.Name, ctx.Log.History.String(), ctx.Command.Verbose)
|
|
c.GHClient.CreateComment(ctx.BaseRepo, ctx.Pull, comment) // nolint: errcheck
|
|
}
|
|
|
|
// logPanics logs and creates a comment on the pull request for panics
|
|
func (c *CommandHandler) logPanics(ctx *CommandContext) {
|
|
if err := recover(); err != nil {
|
|
stack := recovery.Stack(3)
|
|
c.GHClient.CreateComment(ctx.BaseRepo, ctx.Pull, // nolint: errcheck
|
|
fmt.Sprintf("**Error: goroutine panic. This is a bug.**\n```\n%s\n%s```", err, stack))
|
|
ctx.Log.Err("PANIC: %s\n%s", err, stack)
|
|
}
|
|
}
|