CI/CD pipeline management: graphs, matrices, and deployments
What this domain tests
This domain is about the pipeline shape rather than a single job: dependency graphs, matrix expansion, reusable workflows, and the deployment controls (environments, approvals, concurrency, OIDC) that make a release safe to automate.
Job graphs and matrices
needsdefines the DAG; a downstream job waits for all listed jobs and is skipped if any of them fail unless itsifsays otherwise.- Job outputs are written to
$GITHUB_OUTPUTand read asneeds.<job>.outputs.<name>. Outputs containing secrets are skipped, so the value arrives empty. - A matrix can produce at most 256 jobs per workflow run.
excluderemoves combinations;includeadds keys to matching combinations and creates extra jobs for entries that match none. fail-fast: falselets the remaining matrix legs finish so you see every failure at once;max-parallellimits concurrent legs.
Reusable workflows versus composite actions
- Reusable workflows use
on: workflow_calland are called at job level withuses: org/repo/.github/workflows/x.yml@ref, passingwith:andsecrets: inherit. Nesting is limited to four levels. - Composite actions (
runs: using: composite) wrap steps and cannot receivesecretsdirectly.
Environments and deployment control
- Adding
environment:to a job unlocks environment secrets and protection rules: required reviewers, wait timers, and allowed deployment branches. - Use
permissions: id-token: writeplus a cloud trust policy for OIDC instead of stored long-lived keys. - Put
concurrencyon deploy jobs withcancel-in-progress: falseso a release in flight is never cut off.
Worked example
jobs:
build:
runs-on: ubuntu-latest
outputs: {tag: "${{ steps.meta.outputs.tag }}"}
steps:
- id: meta
run: echo "tag=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
deploy:
needs: build
if: needs.build.outputs.tag != ''
environment: ${{ matrix.env }}
strategy: {matrix: {env: [staging, production]}, max-parallel: 1}
concurrency: {group: deploy-${{ matrix.env }}, cancel-in-progress: false}
runs-on: ubuntu-latest
steps:
- run: ./deploy.sh ${{ needs.build.outputs.tag }}
Reasoning: build once and promote the same tag; the if guard catches an empty output instead of deploying undefined; per-environment concurrency serialises deploys while allowing staging and production to differ.
Traps that cost marks
matrix.includeadding a stray key can create an extra unintended job.- Environment protection rules only apply when the job declares
environment:; environment secrets are invisible otherwise. - Artifacts must be uploaded and downloaded explicitly between jobs - runners share no filesystem.
cancel-in-progress: trueon a production deploy group can kill a release mid-rollout.