Skip to content
107 changes: 107 additions & 0 deletions .github/workflows/notify-consumers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: Notify Consumers

# workflow_run fires on EVERY completion of Main (any branch, any outcome),
# so this workflow only actually runs for:
# - a successful Main build on `main` (the commit-tagged image was just
# published, e.g. a PR merged to main) -> triggered_by=merge, or
# - a manual workflow_dispatch (re-trigger a stuck/skipped pin update)
# -> triggered_by=manual
# A failed Main run, or a successful run on a PR/feature branch, is
# skipped: no image was published for consumers to pin to.

# To manually re-trigger a consumer pin update, run:
# `gh workflow run "Notify Consumers" --ref main`

on: # yamllint disable-line rule:truthy
workflow_run:
workflows: ["Main"]
types: [completed]
workflow_dispatch: {}

concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_sha || github.sha }}
cancel-in-progress: true

# Default permissions for all jobs
permissions: {}

jobs:
determine-inputs:
name: "Determine trigger inputs"
runs-on: ubuntu-24.04
permissions:
actions: read
if: >-
github.event_name == 'workflow_dispatch' ||
Comment thread
TonyCTHsu marked this conversation as resolved.
(github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'main')
outputs:
commit: ${{ steps.inputs.outputs.commit }}
triggered_by: ${{ steps.inputs.outputs.triggered_by }}
run_url: ${{ steps.inputs.outputs.run_url }}
steps:
- name: Determine trigger inputs
id: inputs
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "commit=${{ github.sha }}" >> "$GITHUB_OUTPUT"
echo "triggered_by=manual" >> "$GITHUB_OUTPUT"
else
echo "commit=${{ github.event.workflow_run.head_sha }}" >> "$GITHUB_OUTPUT"
echo "triggered_by=merge" >> "$GITHUB_OUTPUT"
fi
echo "run_url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> "$GITHUB_OUTPUT"

# A manual dispatch can be run against any ref at any time, including
# before Main has built and published an image for that commit.
- name: Verify image was published for this commit
env:
GH_TOKEN: ${{ github.token }}
COMMIT: ${{ steps.inputs.outputs.commit }}
run: |
conclusion=$(gh api "repos/${{ github.repository }}/actions/runs?head_sha=$COMMIT&status=completed" \
--jq '[.workflow_runs[] | select(.name == "Main")] | sort_by(.run_started_at) | last | .conclusion // "none"')
if [ "$conclusion" != "success" ]; then
echo "::error::No successful Main run found for commit $COMMIT (found: $conclusion). The image for this commit may not be published yet."
exit 1
fi

notify:
name: "Notify ${{ matrix.repo }}"
needs: determine-inputs
runs-on: ubuntu-24.04
permissions:
id-token: write
strategy:
fail-fast: false
matrix:
include:
# To add a new consumer: add a { repo, policy } entry below, add a
# matching self.<policy> dd-octo-sts policy in the consumer repo,
# get a cross-repo dd-octo-sts grant provisioned for images-rb to
# dispatch into it, and make sure the consumer repo actually has a
# workflow listening for the images-updated repository_dispatch
# event.
- repo: DataDog/dd-trace-rb
policy: images-rb.notify-dd-trace-rb
steps:
- name: Get GitHub Token via dd-octo-sts
id: generate-token
uses: DataDog/dd-octo-sts-action@96a25462dbcb10ebf0bfd6e2ccc917d2ab235b9a # v1.0.4
with:
scope: ${{ matrix.repo }}
policy: ${{ matrix.policy }}

# There appers to be a race condition; wait it out a bit
# See: https://datadoghq.atlassian.net/browse/APMLP-1305
- name: Wait for token propagation
run: sleep 30

- name: Dispatch to ${{ matrix.repo }}
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
run: |
gh api "repos/${{ matrix.repo }}/dispatches" \
-f event_type=images-updated \
-f "client_payload[commit]=${{ needs.determine-inputs.outputs.commit }}" \
-f "client_payload[source_run_url]=${{ needs.determine-inputs.outputs.run_url }}" \
-f "client_payload[triggered_by]=${{ needs.determine-inputs.outputs.triggered_by }}"