uses format #14
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Pipelines | |
run-name: Run Gruntwork Pipelines | |
on: | |
workflow_call: | |
inputs: | |
# This field can be overriden to customize the runner used for pipelines | |
# workflows. | |
# | |
# IMPORTANT: To use self-hosted runners this workflow must be hosted in | |
# the same GitHub organization as your infra-live repository. | |
# See https://docs.github.com/en/actions/using-workflows/reusing-workflows#using-self-hosted-runners | |
# | |
# The value must be an escaped JSON string that will be decoded to the | |
# jobs.runs-on field | |
# See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idruns-on | |
# | |
# For example: | |
# - A simple github runner: "\"ubuntu-22.04\"" | |
# - A list of labels: "[\"self-hosted\", \"linux\"]" | |
# - A map: "{group: \"ubuntu-runners\", labels: \"ubuntu-20.04-16core\"}" | |
runner: | |
type: string | |
default: '"ubuntu-latest"' | |
secrets: | |
PIPELINES_READ_TOKEN: | |
required: true | |
INFRA_ROOT_WRITE_TOKEN: | |
required: true | |
ORG_REPO_ADMIN_TOKEN: | |
required: false | |
env: | |
PIPELINES_CLI_VERSION: v0.29.0-rc1 | |
PIPELINES_ACTIONS_VERSION: 2024-08-27_gruntcon_githubapp | |
BOILERPLATE_VERSION: v0.5.16 | |
GRUNTWORK_INSTALLER_VERSION: v0.0.40 | |
# Disables all executions of terragrunt. This is useful for debugging | |
# specifics of pipelines actions/workflows and bypassing the (usually time consuming) | |
# actual IaC execution. | |
SKIP_TERRAGRUNT: false | |
# GitHub Actions tends to hit resource exhaustion and kill running jobs | |
# if we leave parallelism unbounded, so we set the max to 10 for a sane default. | |
TERRAGRUNT_PARALLELISM: 10 | |
jobs: | |
pipelines_orchestrate: | |
name: Detect Infrastructure Changes | |
runs-on: ${{ fromJSON(inputs.runner) }} | |
steps: | |
- name: Fetch Gruntwork Read Token | |
id: fetch-piplines-gruntwork-read-token | |
uses: gruntwork-test/pipelines-credentials | |
with: | |
PIPELINES_TOKEN_PATH: "pipelines-read/gruntwork-io" | |
FALLBACK_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
- name: Fetch Org Read Token | |
id: fetch-piplines-org-read-token | |
uses: gruntwork-test/pipelines-credentials | |
with: | |
PIPELINES_TOKEN_PATH: "pipelines-read/${{ env.GITHUB_REPOSITORY_OWNER }}" | |
FALLBACK_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
- name: Checkout Pipelines Actions | |
id: checkout_actions | |
uses: actions/checkout@v4 | |
with: | |
path: pipelines-actions | |
repository: gruntwork-io/pipelines-actions | |
ref: ${{ env.PIPELINES_ACTIONS_VERSION }} | |
token: ${{ steps.fetch-pipelines-gruntwork-read-token.PIPELINES_TOKEN }} | |
- name: Validate PIPELINES_READ_TOKEN | |
if: always() && steps.checkout_actions.conclusion != 'success' | |
env: | |
GH_TOKEN: ${{ github.token }} | |
GITHUB_ORG: ${{ github.repository }} | |
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
shell: bash | |
run: | | |
logs_url="https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" | |
msg=$(printf "<h2>❌ Plan for $PR_HEAD_SHA</h2>❌ Gruntwork Pipelines was unable to checkout the <code>pipelines-actions</code> repository. Please ensure the <code>PIPELINES_READ_TOKEN</code> is valid and unexpired. <a href=\"https://docs.gruntwork.io/pipelines/security/machine-users#ci-read-only-user\">Learn More</a><br><br><br><a href=\"$logs_url\">View full logs</a>") | |
echo "::error:: $msg" | |
echo "$msg" >> "$GITHUB_STEP_SUMMARY" | |
pull_number=$(jq --raw-output .pull_request.number "$GITHUB_EVENT_PATH") | |
gh pr comment $pull_number -b "$msg" -R $GITHUB_ORG || true # || true incase this fails on a non-PR run | |
- name: Check out repo code | |
uses: actions/checkout@v4 | |
with: | |
path: infra-live-repo | |
fetch-depth: 0 | |
- name: Preflight Checks | |
uses: ./pipelines-actions/.github/actions/pipelines-preflight-action | |
with: | |
IS_ROOT: "true" | |
PIPELINES_READ_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
INFRA_ROOT_WRITE_TOKEN: ${{ secrets.INFRA_ROOT_WRITE_TOKEN }} | |
ORG_REPO_ADMIN_TOKEN: ${{ secrets.ORG_REPO_ADMIN_TOKEN }} | |
- name: Pipelines Orchestrate | |
id: orchestrate | |
uses: ./pipelines-actions/.github/actions/pipelines-orchestrate | |
with: | |
token: ${{ secrets.PIPELINES_READ_TOKEN }} | |
outputs: | |
pipelines_jobs: ${{ steps.orchestrate.outputs.jobs }} | |
pipelines_execute: | |
name: ${{ contains(matrix.jobs.Action.Command, 'plan') && 'Plan' || 'Apply' }} - ${{ matrix.jobs.ChangeType }} - ${{ matrix.jobs.WorkingDirectory }} | |
needs: [pipelines_orchestrate] | |
runs-on: ${{ fromJSON(inputs.runner) }} | |
# GHA can't check for length, so we just check if there is an item in the 0 index | |
if: fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0] != null | |
strategy: | |
fail-fast: false | |
matrix: | |
jobs: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs) }} | |
steps: | |
- name: Checkout Pipelines Actions | |
uses: actions/checkout@v4 | |
with: | |
path: pipelines-actions | |
repository: gruntwork-io/pipelines-actions | |
ref: ${{ env.PIPELINES_ACTIONS_VERSION }} | |
token: ${{ secrets.PIPELINES_READ_TOKEN }} | |
- name: Check out repo code | |
uses: actions/checkout@v4 | |
with: | |
path: infra-live-repo | |
fetch-depth: 0 | |
- name: Bootstrap Workflow | |
id: gruntwork_context | |
uses: ./pipelines-actions/.github/actions/pipelines-bootstrap | |
with: | |
token: ${{ secrets.PIPELINES_READ_TOKEN }} | |
change_type: ${{ matrix.jobs.ChangeType }} | |
branch: ${{ matrix.jobs.Ref }} | |
working_directory: ${{ matrix.jobs.WorkingDirectory }} | |
account_id: ${{ matrix.jobs.AccountId }} | |
terragrunt_command: ${{ matrix.jobs.Action.Command }} ${{ matrix.jobs.Action.Args }} | |
additional_data: ${{ toJson(matrix.jobs.AdditionalData) }} | |
child_account_id: ${{ matrix.jobs.AdditionalData.ChildAccountId }} | |
account_names: ${{ matrix.jobs.AdditionalData.AccountNames }} | |
# TODO: This should be "first_new_account_name". | |
new_account_name: ${{ matrix.jobs.NewAccounts[0].Name }} | |
# To learn more about customizing Pipelines see our documentation at https://docs.gruntwork.io/pipelines/maintain/extending/ | |
- name: "[Baseline]: Pre Provision New Account Custom Action" | |
uses: ./pipelines-actions/.github/custom-actions/pre-provision-new-account | |
if: ${{ steps.gruntwork_context.outputs.action == 'PROVISION_ACCOUNT' }} | |
with: | |
PIPELINES_READ_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
INFRA_ROOT_WRITE_TOKEN: ${{ secrets.INFRA_ROOT_WRITE_TOKEN }} | |
gruntwork_context: ${{ toJson(steps.gruntwork_context.outputs) }} | |
- name: "[ProvisionAccount]: Provision New Account" | |
id: provision_new_account | |
if: ${{ steps.gruntwork_context.outputs.action == 'PROVISION_ACCOUNT' }} | |
uses: ./pipelines-actions/.github/actions/pipelines-provision-account-action | |
with: | |
PIPELINES_READ_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
INFRA_ROOT_WRITE_TOKEN: ${{ secrets.INFRA_ROOT_WRITE_TOKEN }} | |
gruntwork_context: ${{ toJson(steps.gruntwork_context.outputs) }} | |
- name: "[Baseline]: Post Provision New Account Custom Action" | |
uses: ./pipelines-actions/.github/custom-actions/post-provision-new-account | |
if: ${{ steps.gruntwork_context.outputs.action == 'PROVISION_ACCOUNT' }} | |
with: | |
PIPELINES_READ_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
INFRA_ROOT_WRITE_TOKEN: ${{ secrets.INFRA_ROOT_WRITE_TOKEN }} | |
gruntwork_context: ${{ toJson(steps.gruntwork_context.outputs) }} | |
baseline_pull_request_url: ${{ steps.provision_new_account.outputs.pull_request_url }} | |
- name: "[Baseline]: Pre Baseline Core Account Action" | |
uses: ./pipelines-actions/.github/custom-actions/pre-baseline-core-accounts | |
if: steps.gruntwork_context.outputs.action == 'BASELINE_ACCOUNT' | |
with: | |
PIPELINES_READ_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
gruntwork_context: ${{ toJson(steps.gruntwork_context.outputs) }} | |
# Run the core accounts baselines(shared, logs, security, etc. to ensure the account is setup correctly) | |
- name: "Run core accounts baselines" | |
id: core_accounts_baselines | |
if: steps.gruntwork_context.outputs.action == 'BASELINE_ACCOUNT' | |
# TODO: Rename this as pipelines-apply-core-baselines or something similar | |
uses: ./pipelines-actions/.github/actions/pipelines-baseline-account-action | |
with: | |
PIPELINES_READ_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
gruntwork_context: ${{ toJson(steps.gruntwork_context.outputs) }} | |
- name: "[Baseline]: Post Baseline Core Account Action" | |
uses: ./pipelines-actions/.github/custom-actions/post-baseline-core-accounts | |
if: steps.gruntwork_context.outputs.action == 'BASELINE_ACCOUNT' | |
with: | |
PIPELINES_READ_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
gruntwork_context: ${{ toJson(steps.gruntwork_context.outputs) }} | |
- name: "[TerragruntExecute]: Authenticate with AWS and then Invoke Terragrunt" | |
id: terragrunt | |
if: ${{ steps.gruntwork_context.outputs.action == 'TERRAGRUNT_EXECUTE' }} | |
uses: ./pipelines-actions/.github/actions/pipelines-execute | |
env: | |
TERRAGRUNT_AUTH_PROVIDER_CMD: "pipelines auth terragrunt-credentials --ci github-actions --cloud aws --wd ." | |
with: | |
token: ${{ secrets.PIPELINES_READ_TOKEN }} | |
tf_binary: ${{ steps.gruntwork_context.outputs.tf_binary }} | |
working_directory: ${{ steps.gruntwork_context.outputs.working_directory }} | |
terragrunt_command: ${{ steps.gruntwork_context.outputs.terragrunt_command }} | |
infra_live_repo_branch: ${{ steps.gruntwork_context.outputs.branch }} | |
gruntwork_config_file: ${{ steps.gruntwork_context.outputs.gruntwork_config_file }} | |
infra_live_repo: "." | |
infra_live_directory: "." | |
deploy_branch_name: ${{ steps.gruntwork_context.outputs.deploy_branch_name }} | |
- name: Update comment | |
uses: ./pipelines-actions/.github/actions/pipelines-status-update | |
if: always() | |
with: | |
step_name: ${{ matrix.jobs.ChangeType }} | |
step_working_directory: ${{ matrix.jobs.WorkingDirectory }} | |
step_status: ${{ (steps.provision_new_account.conclusion == 'success' || steps.terragrunt.conclusion == 'success' || steps.core_accounts_baselines.conclusion == 'success') && 'success' || 'failed' }} | |
step_details: ${{ steps.terragrunt.outputs.formatted_plan_output }} | |
step_details_extended_log: ${{ steps.terragrunt.outputs.execute_stdout_log }} | |
pull_request_number: ${{ steps.gruntwork_context.outputs.pr_number }} | |
outputs: | |
account_id: ${{ matrix.jobs.AccountId }} | |
branch: ${{ steps.gruntwork_context.outputs.branch }} | |
action: ${{ steps.gruntwork_context.outputs.action }} | |
working_directory: ${{ steps.gruntwork_context.outputs.working_directory }} | |
terragrunt_command: ${{ steps.gruntwork_context.outputs.terragrunt_command }} | |
additional_data: ${{ steps.gruntwork_context.outputs.additional_data }} | |
child_account_id: ${{ steps.gruntwork_context.outputs.child_account_id }} | |
pr_number: ${{ steps.gruntwork_context.outputs.pr_number }} | |
delegate_management: ${{ steps.gruntwork_context.outputs.delegate_management }} | |
pipelines_apply_baselines: | |
name: Baseline Child Account ${{ contains(fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].Action.Command, 'plan') && 'Plan' || 'Apply' }} - ${{ matrix.jobs.Name }} (${{ matrix.jobs.ID }}) | |
needs: [pipelines_orchestrate, pipelines_execute] | |
runs-on: ${{ fromJSON(inputs.runner) }} | |
# GHA can't check for length, so we just check if there is an item in the 0 index | |
if: fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].NewAccounts[0] != null | |
strategy: | |
fail-fast: false | |
matrix: | |
jobs: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].NewAccounts }} | |
steps: | |
- name: Checkout Pipelines Actions | |
uses: actions/checkout@v4 | |
with: | |
path: pipelines-actions | |
repository: gruntwork-io/pipelines-actions | |
ref: ${{ env.PIPELINES_ACTIONS_VERSION }} | |
token: ${{ secrets.PIPELINES_READ_TOKEN }} | |
- name: Check out repo code | |
uses: actions/checkout@v4 | |
with: | |
path: infra-live-repo | |
fetch-depth: 0 | |
- name: Update comment | |
uses: ./pipelines-actions/.github/actions/pipelines-status-update | |
with: | |
step_name: Baseline Child Account ${{ matrix.jobs.Name }} | |
step_status: "in_progress" | |
pull_request_number: ${{ needs.pipelines_execute.outputs.pr_number }} | |
- name: Bootstrap Workflow | |
id: gruntwork_context | |
uses: ./pipelines-actions/.github/actions/pipelines-bootstrap | |
with: | |
token: ${{ secrets.PIPELINES_READ_TOKEN }} | |
change_type: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].ChangeType }} | |
branch: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].Ref }} | |
working_directory: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].WorkingDirectory }} | |
account_id: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].AccountId }} | |
terragrunt_command: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].Action.Command }} ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].Action.Args }} | |
additional_data: ${{ toJson(fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].AdditionalData) }} | |
account_names: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].AdditionalData.AccountNames }} | |
child_account_id: ${{ matrix.jobs.ID }} | |
new_account_name: ${{ matrix.jobs.Name }} | |
# To learn more about customizing Pipelines see our documentation at https://docs.gruntwork.io/pipelines/maintain/extending/ | |
- name: "[Baseline]: Pre Baseline Child Account Action" | |
uses: ./pipelines-actions/.github/custom-actions/pre-baseline-child-account | |
with: | |
PIPELINES_READ_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
account_id: ${{ matrix.jobs.ID }} | |
account_name: ${{ matrix.jobs.Name }} | |
job: ${{ toJson(fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0]) }} | |
gruntwork_context: ${{ toJson(steps.gruntwork_context.outputs) }} | |
- name: "[Baseline]: Baseline the Child Account" | |
id: baseline_child_account | |
uses: ./pipelines-actions/.github/actions/pipelines-baseline-child-account-action | |
with: | |
PIPELINES_READ_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
account_id: ${{ matrix.jobs.ID }} | |
account_name: ${{ matrix.jobs.Name }} | |
job: ${{ toJson(fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0]) }} | |
gruntwork_context: ${{ toJson(steps.gruntwork_context.outputs) }} | |
- name: "[Baseline]: Post Baseline Child Account Action" | |
uses: ./pipelines-actions/.github/custom-actions/post-baseline-child-account | |
with: | |
PIPELINES_READ_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
account_id: ${{ matrix.jobs.ID }} | |
account_name: ${{ matrix.jobs.Name }} | |
job: ${{ toJson(fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0]) }} | |
gruntwork_context: ${{ toJson(steps.gruntwork_context.outputs) }} | |
- name: Update comment | |
uses: ./pipelines-actions/.github/actions/pipelines-status-update | |
if: always() | |
with: | |
step_name: Baseline Child Account ${{ matrix.jobs.Name }} | |
step_status: ${{ steps.baseline_child_account.conclusion == 'success' && 'success' || 'failed' }} | |
step_details: ${{ steps.baseline_child_account.outputs.formatted_plan_output || 'Check the logs for more details.' }} | |
step_details_extended_log: ${{ steps.baseline_child_account.outputs.execute_stdout_log }} | |
pull_request_number: ${{ needs.pipelines_execute.outputs.pr_number }} | |
pipelines_setup_delegated_repo: | |
name: "Setup Delegated Repo" | |
needs: [pipelines_orchestrate, pipelines_apply_baselines, pipelines_execute] | |
runs-on: ${{ fromJSON(inputs.runner) }} | |
# GHA can't check for length, so we just check if there is an item in the 0 index | |
if: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].NewAccounts[0] != null && needs.pipelines_execute.outputs.delegate_management == 'true' && needs.pipelines_execute.outputs.terragrunt_command == 'run-all apply' }} | |
steps: | |
- name: Checkout Pipelines Actions | |
uses: actions/checkout@v4 | |
with: | |
path: pipelines-actions | |
repository: gruntwork-io/pipelines-actions | |
ref: ${{ env.PIPELINES_ACTIONS_VERSION }} | |
token: ${{ secrets.PIPELINES_READ_TOKEN }} | |
- name: Check out repo code | |
uses: actions/checkout@v4 | |
with: | |
path: infra-live-repo | |
fetch-depth: 0 | |
- name: Bootstrap Workflow | |
id: gruntwork_context | |
uses: ./pipelines-actions/.github/actions/pipelines-bootstrap | |
with: | |
token: ${{ secrets.PIPELINES_READ_TOKEN }} | |
change_type: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].ChangeType }} | |
branch: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].Ref }} | |
working_directory: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].WorkingDirectory }} | |
account_id: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].AccountId }} | |
terragrunt_command: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].Action.Command }} ${{ needs.pipelines_orchestrate.outputs.pipelines_jobs[0].Action.Args }} | |
additional_data: ${{ toJson(fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].AdditionalData) }} | |
child_account_id: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].AdditionalData.ChildAccountId }} | |
account_names: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].AdditionalData.AccountNames }} | |
# This is just to help bootstrap find one of the (possibly several) new account request files | |
# Inside those files is some shared config that we need to setup access control such as | |
# the delegated_repo_name (which is the same in all the new request files) | |
new_account_name: ${{ fromJson(needs.pipelines_orchestrate.outputs.pipelines_jobs)[0].NewAccounts[0].Name }} | |
- name: "Create Access Control PR" | |
id: access_control_pr | |
uses: ./pipelines-actions/.github/actions/pipelines-provision-access-control-action | |
with: | |
gruntwork_context: ${{ toJson(steps.gruntwork_context.outputs) }} | |
PIPELINES_READ_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
ORG_REPO_ADMIN_TOKEN: ${{ secrets.ORG_REPO_ADMIN_TOKEN }} | |
- name: "Create and bootstrap delegated Repo" | |
id: provision_delegated_repo | |
uses: ./pipelines-actions/.github/actions/pipelines-provision-repo-action | |
with: | |
gruntwork_context: ${{ toJson(steps.gruntwork_context.outputs) }} | |
access_control_pull_request_url: ${{ steps.access_control_pr.outputs.pull_request_url }} | |
PIPELINES_READ_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
ORG_REPO_ADMIN_TOKEN: ${{ secrets.ORG_REPO_ADMIN_TOKEN }} | |
# To learn more about customizing Pipelines see our documentation at https://docs.gruntwork.io/pipelines/maintain/extending/ | |
- name: "Post create delegated repo custom actions" | |
uses: ./pipelines-actions/.github/custom-actions/post-create-delegated-repo | |
with: | |
gruntwork_context: ${{ toJson(steps.gruntwork_context.outputs) }} | |
access_control_pull_request_url: ${{ steps.access_control_pr.outputs.pull_request_url }} | |
PIPELINES_READ_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | |
ORG_REPO_ADMIN_TOKEN: ${{ secrets.ORG_REPO_ADMIN_TOKEN }} | |
delegated_repo_pull_request_url: ${{ steps.provision_delegated_repo.outputs.pull_request_url }} |