Atlantis Hook Execution#
Overview#
Atlantis supports pre-workflow hooks and post-workflow hooks β shell commands that run before or after default/custom workflows execute on a pull request. Unlike custom workflow run steps, hooks run outside Atlantis command workflows and do not surface output as PR comments. They are configured exclusively in the Server-Side Repo Config under the repos key β not in per-repo atlantis.yaml files.
A primary use case for pre-hooks is dynamic repo config generation: running a script that writes atlantis.yaml before Atlantis parses it. Post-hooks are commonly used for cross-project cost estimation summaries (e.g., aggregating Infracost outputs after all plan workflows complete).
Configuration#
Hooks are specified under repos[].pre_workflow_hooks or repos[].post_workflow_hooks in the server config.
repos:
- id: /.*/
pre_workflow_hooks:
- run: ./gen-atlantis-yaml.sh
description: Generate atlantis.yaml
commands: plan
shell: bash
shellArgs: -c
post_workflow_hooks:
- run: ./notify.sh
description: Notify on plan or apply
commands: plan, apply
Supported fields per hook (post-workflow-hooks docs, pre-workflow-hooks docs):
| Field | Default | Description |
|---|---|---|
run | (required) | Shell command to execute |
description | auto-numbered | Label shown in VCS commit status |
commands | (all commands) | Comma-delimited command filter (e.g. plan, apply) |
shell | sh | Shell binary to use |
shellArgs | -c | Shell arguments |
The valid.WorkflowHook struct holds exactly these fields: RunCommand, StepDescription, Commands, Shell, ShellArgs . There are no directory-scoping fields β hooks are matched at the repo level only.
Invocation Flow#
Both hook types follow the same lifecycle, orchestrated by DefaultCommandRunner in server/events/command_runner.go:
RunCommentCommand / RunAutoplanCommand
β
βββ shouldSkipPreWorkflowHooks? ββyesβββΆ return (no hooks, no command)
β
βββ PreWorkflowHooksCommandRunner.RunPreHooks() β pre hooks
β
βββ cmdRunner.Run() β plan / apply / etc.
β
βββ if ctx.CommandSkipped β return (no post hooks)
β
βββ PostWorkflowHooksCommandRunner.RunPostHooks() β post hooks
- Pre hooks β
RunPreHooks: collects hooks fromGlobalCfgrepos matching by repo ID only , acquires a workspace lock, clones the repo, and executes hooks in order. - Post hooks β
RunPostHooks: matches by both repo ID and branch , and additionally surfacesCommandHasErrorsandCommandNamein the hook context , useful for conditional post-hook behavior. - Both runners short-circuit immediately if no hooks are configured for the repo .
VCS Commit Status#
Each hook posts commit status updates: Pending β Success (or Failed) for every hook step. Updates can be suppressed via SuppressVCSStatus on the context .
Command Targeting (commands field)#
By default, every hook runs for every Atlantis command. Set commands to restrict execution to specific commands. The check is a substring match against the comma-separated string:
if hook.Commands != "" && !strings.Contains(hook.Commands, ctx.CommandName) {
continue // skip this hook
}
commands: plan, apply matches both plan and apply. Values must match the command names exactly as Atlantis uses them (e.g., plan, apply, import, state).
Two environment variables are available inside hook scripts for conditional logic :
COMMAND_NAMEβ the triggering command (plan,apply, etc.)COMMAND_HAS_ERRORSβ post-hooks only;trueif the preceding command had errors, otherwisefalse
Directory-Based Skip Logic (autodiscover.ignore_paths)#
Hooks have no directory-scoping configuration of their own. However, when a user targets a specific directory (via -d <dir>) that matches an autodiscover.ignore_paths pattern, hooks are skipped entirely:
PlanCommandRunner.ShouldSkipPreWorkflowHooksand its apply equivalent delegate toMarkCommandSkippedIfIgnoredTarget.- That function sets
ctx.CommandSkipped = truewhencmd.RepoRelDirmatches an ignored path (and no project name was explicitly targeted) . - If the skip is triggered before pre-hooks, pre-hooks are not run .
- If
ctx.CommandSkippedis true after command execution, post-hooks are also skipped .
Special case β pre-hooks updating repo config: If pre-hooks are configured (e.g., to generate atlantis.yaml), DefaultCommandRunner runs them even when the target is initially ignored, then re-evaluates the skip via ctx.PreferLocalRepoCfgForTargetedIgnore. If the directory is still ignored after hooks run, execution stops before the command .
Pre-Hook Error Handling#
Pre-hook failures do not block command execution by default. Control this with the --fail-on-pre-workflow-hook-error server flag :
- Flag set: Atlantis posts the error as a PR comment, marks plan/apply commit status as failed, and aborts the command .
- Flag unset: error is logged and execution continues .
Post-hook errors are logged but do not affect PR state or commit statuses .
Key Source Files#
| File | Purpose |
|---|---|
pre_workflow_hooks_command_runner.go | Pre-hook runner: repo matching, lock, clone, execute |
post_workflow_hooks_command_runner.go | Post-hook runner: same pattern + error/command context |
command_runner.go | Orchestrates pre β command β post hook lifecycle |
plan_command_runner.go | ShouldSkipPreWorkflowHooks for plan |
valid.WorkflowHook (global_cfg.go) | Hook configuration struct |
models.WorkflowHookCommandContext (models.go) | Execution context for hook runners |
project_command_builder.go β MarkCommandSkippedIfIgnoredTarget | Directory-based hook skip logic |