Merge branch 'main' into execute-orchestrate-custom-actions #1
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"' | ||
api_base_url: | ||
type: string | ||
default: "https://api.prod.app.gruntwork.io/api/v1" | ||
pipelines_binary_url: | ||
type: string | ||
default: "" | ||
description: "Override where we fetch pipelines from, used for internal testing" | ||
secrets: | ||
PIPELINES_READ_TOKEN: | ||
required: true | ||
PR_CREATE_TOKEN: | ||
required: false | ||
env: | ||
PIPELINES_CLI_VERSION: v0.36.2 | ||
PIPELINES_ACTIONS_VERSION: v3.4.3# TODO: update to whatever version comes after we merge matching actions PR | ||
# 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: Record workflow env vars | ||
env: | ||
PIPELINES_BINARY_URL: ${{ inputs.pipelines_binary_url }} | ||
run: | | ||
time_now=$(date -u +"%s") | ||
echo "PIPELINES_JOB_START_TIME=$time_now" >> $GITHUB_ENV | ||
echo "PIPELINES_BINARY_URL=$PIPELINES_BINARY_URL" >> $GITHUB_ENV | ||
- name: Fetch Gruntwork Read Token | ||
id: pipelines-gruntwork-read-token | ||
uses: gruntwork-io/pipelines-credentials@v1 | ||
with: | ||
PIPELINES_TOKEN_PATH: "pipelines-read/gruntwork-io" | ||
FALLBACK_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | ||
api_base_url: ${{ inputs.api_base_url }} | ||
- name: Fetch Org Read Token | ||
id: pipelines-customer-org-read-token | ||
uses: gruntwork-io/pipelines-credentials@v1 | ||
with: | ||
PIPELINES_TOKEN_PATH: pipelines-read/${{ github.repository_owner }} | ||
FALLBACK_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | ||
api_base_url: ${{ inputs.api_base_url }} | ||
- name: Fetch Create PR Token | ||
id: pipelines-propose-infra-change-token | ||
uses: gruntwork-io/pipelines-credentials@v1 | ||
with: | ||
PIPELINES_TOKEN_PATH: propose-infra-change/${{ github.repository_owner }} | ||
FALLBACK_TOKEN: ${{ secrets.PR_CREATE_TOKEN }} | ||
api_base_url: ${{ inputs.api_base_url }} | ||
- 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.pipelines-gruntwork-read-token.outputs.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 | ||
token: ${{ steps.pipelines-customer-org-read-token.outputs.PIPELINES_TOKEN }} | ||
- name: Preflight Checks | ||
uses: ./pipelines-actions/.github/actions/pipelines-preflight-action | ||
with: | ||
PIPELINES_READ_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | ||
PIPELINES_GRUNTWORK_READ_TOKEN: ${{ steps.pipelines-gruntwork-read-token.outputs.PIPELINES_TOKEN }} | ||
PIPELINES_CUSTOMER_ORG_READ_TOKEN: ${{ steps.pipelines-customer-org-read-token.outputs.PIPELINES_TOKEN }} | ||
PR_COMMENT_WRITE_TOKEN: ${{ steps.pipelines-propose-infra-change-token.outputs.PIPELINES_TOKEN }} | ||
- name: Pre Orchestrate Custom Action | ||
uses: ./pipelines-actions/.github/custom-actions/pre-orchestrate | ||
with: | ||
PIPELINES_GRUNTWORK_READ_TOKEN: ${{ steps.pipelines-gruntwork-read-token.outputs.PIPELINES_TOKEN }} | ||
PIPELINES_CUSTOMER_ORG_READ_TOKEN: ${{ steps.pipelines-customer-org-read-token.outputs.PIPELINES_TOKEN }} | ||
PR_COMMENT_WRITE_TOKEN: ${{ steps.pipelines-propose-infra-change-token.outputs.PIPELINES_TOKEN }} | ||
- name: Pipelines Orchestrate | ||
id: orchestrate | ||
uses: ./pipelines-actions/.github/actions/pipelines-orchestrate | ||
with: | ||
PIPELINES_GRUNTWORK_READ_TOKEN: ${{ steps.pipelines-gruntwork-read-token.outputs.PIPELINES_TOKEN }} | ||
PIPELINES_CUSTOMER_ORG_READ_TOKEN: ${{ steps.pipelines-customer-org-read-token.outputs.PIPELINES_TOKEN }} | ||
PR_COMMENT_WRITE_TOKEN: ${{ steps.pipelines-propose-infra-change-token.outputs.PIPELINES_TOKEN }} | ||
- name: Post Orchestrate Custom Action | ||
uses: ./pipelines-actions/.github/custom-actions/post-orchestrate | ||
with: | ||
PIPELINES_GRUNTWORK_READ_TOKEN: ${{ steps.pipelines-gruntwork-read-token.outputs.PIPELINES_TOKEN }} | ||
PIPELINES_CUSTOMER_ORG_READ_TOKEN: ${{ steps.pipelines-customer-org-read-token.outputs.PIPELINES_TOKEN }} | ||
PR_COMMENT_WRITE_TOKEN: ${{ steps.pipelines-propose-infra-change-token.outputs.PIPELINES_TOKEN }} | ||
jobs: ${{ steps.orchestrate.outputs.jobs }} | ||
outputs: | ||
pipelines_jobs: ${{ steps.orchestrate.outputs.jobs }} | ||
pipelines_execute: | ||
env: | ||
JOB_NAME: ${{ contains(matrix.jobs.Action.Command, 'plan') && 'Plan' || 'Apply' }} - ${{ matrix.jobs.ChangeType }} - ${{ matrix.jobs.WorkingDirectory }} | ||
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: Record workflow env vars | ||
env: | ||
PIPELINES_BINARY_URL: ${{ inputs.pipelines_binary_url }} | ||
run: | | ||
time_now=$(date -u +"%s") | ||
echo "PIPELINES_JOB_START_TIME=$time_now" >> $GITHUB_ENV | ||
echo "PIPELINES_BINARY_URL=$PIPELINES_BINARY_URL" >> $GITHUB_ENV | ||
- name: Fetch Gruntwork Read Token | ||
id: pipelines-gruntwork-read-token | ||
uses: gruntwork-io/pipelines-credentials@v1 | ||
with: | ||
PIPELINES_TOKEN_PATH: "pipelines-read/gruntwork-io" | ||
FALLBACK_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | ||
api_base_url: ${{ inputs.api_base_url }} | ||
- name: Fetch Org Read Token | ||
id: pipelines-customer-org-read-token | ||
uses: gruntwork-io/pipelines-credentials@v1 | ||
with: | ||
PIPELINES_TOKEN_PATH: pipelines-read/${{ github.repository_owner }} | ||
FALLBACK_TOKEN: ${{ secrets.PIPELINES_READ_TOKEN }} | ||
api_base_url: ${{ inputs.api_base_url }} | ||
- name: Fetch Create PR Token | ||
id: pipelines-propose-infra-change-token | ||
uses: gruntwork-io/pipelines-credentials@v1 | ||
with: | ||
PIPELINES_TOKEN_PATH: propose-infra-change/${{ github.repository_owner }} | ||
FALLBACK_TOKEN: ${{ secrets.PR_CREATE_TOKEN }} | ||
api_base_url: ${{ inputs.api_base_url }} | ||
- name: Checkout Pipelines Actions | ||
uses: actions/checkout@v4 | ||
with: | ||
path: pipelines-actions | ||
repository: gruntwork-io/pipelines-actions | ||
ref: ${{ env.PIPELINES_ACTIONS_VERSION }} | ||
token: ${{ steps.pipelines-gruntwork-read-token.outputs.PIPELINES_TOKEN }} | ||
- name: Check out repo code | ||
uses: actions/checkout@v4 | ||
with: | ||
path: infra-live-repo | ||
fetch-depth: 0 | ||
token: ${{ steps.pipelines-customer-org-read-token.outputs.PIPELINES_TOKEN }} | ||
- name: Bootstrap Workflow | ||
id: gruntwork_context | ||
uses: ./pipelines-actions/.github/actions/pipelines-bootstrap | ||
with: | ||
PIPELINES_GRUNTWORK_READ_TOKEN: ${{ steps.pipelines-gruntwork-read-token.outputs.PIPELINES_TOKEN }} | ||
PIPELINES_CUSTOMER_ORG_READ_TOKEN: ${{ steps.pipelines-customer-org-read-token.outputs.PIPELINES_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 }} | ||
- name: Pre Execute Custom Action | ||
uses: ./pipelines-actions/.github/custom-actions/pre-execute | ||
with: | ||
PIPELINES_GRUNTWORK_READ_TOKEN: ${{ steps.pipelines-gruntwork-read-token.outputs.PIPELINES_TOKEN }} | ||
PIPELINES_CUSTOMER_ORG_READ_TOKEN: ${{ steps.pipelines-customer-org-read-token.outputs.PIPELINES_TOKEN }} | ||
account_id: ${{ matrix.jobs.AccountId }} | ||
account_name: ${{ matrix.jobs.Name }} | ||
job: ${{ toJson(matrix.jobs) }} | ||
gruntwork_context: ${{ toJson(steps.gruntwork_context.outputs) }} | ||
- name: "Run terragrunt ${{ steps.gruntwork_context.outputs.terragrunt_command }} in ${{ steps.gruntwork_context.outputs.working_directory }}" | ||
id: terragrunt | ||
uses: ./pipelines-actions/.github/actions/pipelines-execute | ||
env: | ||
TERRAGRUNT_AUTH_PROVIDER_CMD: "pipelines auth terragrunt-credentials --ci github-actions --cloud aws --wd . --disk-cache-duration-minutes 10" | ||
with: | ||
PIPELINES_GRUNTWORK_READ_TOKEN: ${{ steps.pipelines-gruntwork-read-token.outputs.PIPELINES_TOKEN }} | ||
PIPELINES_CUSTOMER_ORG_READ_TOKEN: ${{ steps.pipelines-customer-org-read-token.outputs.PIPELINES_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: Get Logs URL | ||
id: get_logs_url | ||
uses: ./pipelines-actions/.github/actions/pipelines-get-job-logs-url | ||
if: always() | ||
with: | ||
PIPELINES_CUSTOMER_ORG_READ_TOKEN: ${{ steps.pipelines-customer-org-read-token.outputs.PIPELINES_TOKEN }} | ||
job_name: ${{ env.JOB_NAME }} | ||
step_name_prefix: "Run terragrunt" | ||
- name: Update comment | ||
if: always() | ||
uses: ./pipelines-actions/.github/actions/pipelines-status-update | ||
with: | ||
step_name: ${{ matrix.jobs.ChangeType }} | ||
step_working_directory: ${{ matrix.jobs.WorkingDirectory }} | ||
step_status: ${{ steps.terragrunt.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 }} | ||
step_logs_url: ${{ steps.get_logs_url.outputs.step_logs_url }} | ||
PR_COMMENT_WRITE_TOKEN: ${{ steps.pipelines-propose-infra-change-token.outputs.PIPELINES_TOKEN }} | ||
- name: Post Execute Custom Action | ||
uses: ./pipelines-actions/.github/custom-actions/post-execute | ||
with: | ||
PIPELINES_GRUNTWORK_READ_TOKEN: ${{ steps.pipelines-gruntwork-read-token.outputs.PIPELINES_TOKEN }} | ||
PIPELINES_CUSTOMER_ORG_READ_TOKEN: ${{ steps.pipelines-customer-org-read-token.outputs.PIPELINES_TOKEN }} | ||
account_id: ${{ matrix.jobs.AccountId }} | ||
account_name: ${{ matrix.jobs.Name }} | ||
job: ${{ toJson(matrix.jobs) }} | ||
gruntwork_context: ${{ toJson(steps.gruntwork_context.outputs) }} | ||
formatted_plan_output: ${{ steps.terragrunt.outputs.formatted_plan_output }} | ||
execute_stdout_log: ${{ steps.terragrunt.outputs.execute_stdout_log }} | ||
plan_folder: ${{ steps.terragrunt.outputs.plan_folder }} | ||
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 }} |