CI/CD Pipeline Stages & Automation Gates Markdown Table Template
A pipeline matrix documents what happens between git push and production: each stage, the job that implements it, the event that starts it, where it runs, how long it may take, and whether a failure stops the release. The workflow YAML already contains all of this, but spread across files and nested keys; the table is the one-screen view a reviewer, a new team member, or an on-call engineer can read in thirty seconds.
Edit This Template
Edit cells, add rows, or sort — the Markdown updates livePaste cells from Excel or Google Sheets into the first header to replace the table · Tab / Enter / arrows move · Shift+F10 opens row & column actions
When to Use This Table
It is consulted at specific moments. A contributor’s pull request is blocked and they need to know which check matters. An incident review asks whether a security scan could have caught the bug, and whether it was allowed to fail. A platform team plans a runner migration and needs every job that depends on an ARM image. In each case the Blocking Gate and Trigger Event columns carry the answer, so they must match the repository’s real branch rules, not the intended design.
A trustworthy matrix is generated from, or checked against, the actual workflow files and branch protection settings. It uses the exact job identifiers that appear in the checks list, names runner labels that exist, and orders rows in the sequence work flows through the pipeline. The common failure is drift: someone renames a job, the matrix keeps the old name, and the required check silently waits forever on a pull request.
What Goes in Each Column
| Column | Alignment | What to put here |
|---|---|---|
| Pipeline Stage | left :--- | A human-readable phase name — lint, unit tests, security scan, build, deploy — in the order the pipeline executes. Left-aligned. Keep names stable across repositories so people moving between projects recognise the same stage. |
| Job Identifier | left :--- | The job key from the workflow file in a code span, exactly as it appears in the checks list. For matrix jobs, note that each leg reports a separate check such as test-unit-matrix (22), which is what branch rules must reference. |
| Trigger Event | center :---: | The event that starts the job, using the CI system’s vocabulary where possible: pull request, push to a branch, tag matching v*, schedule, manual dispatch, merge queue. Centered as a short label; mention branch or tag filters. |
| Runner Image | left :--- | The runner label or container image in a code span: ubuntu-24.04, ubuntu-24.04-arm, node:22-bookworm. Moving labels like ubuntu-latest change under you, so pin a version when reproducibility matters and record the runtime versions in brackets. |
| Timeout | right ---: | The configured job timeout, right-aligned with a unit (10m). Set it a little above the normal p95 duration. On GitHub Actions the default is 360 minutes, so a missing timeout-minutes lets a hung job burn hours of runner time. |
| Blocking Gate | center :---: | Whether a failure prevents merging or releasing: Yes only if the check is required by branch protection, a ruleset, or a deployment environment rule. Centered. A job that “should” block but is not marked required is a No. |
How to Fill It In
- 1List the workflow files (
.github/workflows/*.ymlor.gitlab-ci.yml) and copy each job’s key, trigger block, runner, and timeout into a row. Treat the YAML as the source of truth for these four columns. - 2Open the branch protection rules or rulesets for the main branch and note which checks are required. Only those rows get
Yesunder Blocking Gate; for deploy jobs, check environment protection rules and required reviewers as well. - 3Open a recent pull request and compare the checks list with your Job Identifier column. Matrix legs, reusable workflows, and renamed jobs show up here with their real names.
- 4Pull typical durations from the last few weeks of runs and confirm each timeout sits above the slow end. Raise timeouts that keep firing; lower ones that are hours above the real duration.
- 5Order rows from pull request to production and add the matrix to the repository’s contributing guide. Re-check it whenever a workflow file changes, ideally as part of the same review.
Ready-to-Paste Variations
GitHub Actions keys, ready to compare with YAML
Uses the literal workflow keys as headers, which makes it easy to diff against the actual files during review.
| Job | `on:` | `runs-on:` | `timeout-minutes:` | Required check name |
| :--- | :--- | :--- | ---: | :--- |
| `lint` | `pull_request` | `ubuntu-24.04` | 5 | `lint` |
| `test` | `pull_request`, `merge_group` | `ubuntu-24.04` | 10 | `test (22)`, `test (24)` |
| `build-arm` | `push` to `main` | `ubuntu-24.04-arm` | 20 | Not required |
| `deploy` | `push` tags `v*` | `ubuntu-24.04` | 10 | Environment: `production` |Gate ownership
Answers the question that comes up during incidents: what enforced this gate, and who can bypass it?
| Gate | Enforced by | Can be bypassed by |
| :--- | :--- | :--- |
| Lint and tests pass | Branch ruleset: required status checks | Repository admins, if bypass is allowed |
| One approving review | Branch ruleset: pull request rule | Repository admins, if bypass is allowed |
| Production approval | Environment protection: required reviewers | Nobody outside the reviewer list |
| Security scan clean | Not enforced (advisory) | Anyone; failures are reported only |GitLab CI equivalent
The same matrix in GitLab terms, where blocking behaviour is controlled per job with allow_failure.
| Stage | Job | `rules` | `image` | `timeout` | `allow_failure` |
| :--- | :--- | :--- | :--- | ---: | :---: |
| `test` | `unit` | Merge request pipelines | `node:22` | 10m | `false` |
| `test` | `sast` | Merge requests and schedules | `semgrep/semgrep` | 15m | `true` |
| `deploy` | `production` | Tags matching `v*` | `alpine:3.20` | 10m | `false` |Common Mistakes
Marking a job as blocking in the table when no rule actually requires it.
A failing job only blocks a merge if branch protection or a ruleset lists it as required. Check the settings page and either add the requirement or change the row to
No.Renaming a job without updating the required check.
Required checks match by name. After a rename the old check never reports and pull requests wait on “Expected” indefinitely. Update the rule in the same change and keep the matrix in sync.
Putting
pathsfilters on a workflow whose checks are required.When path filtering skips a whole workflow, its required checks stay pending and block the merge. Filter inside the job with a conditional step or a changed-files action, so the check still reports.
Listing runner labels that do not exist, or relying on
ubuntu-latestfor builds that must be reproducible.Copy labels from your CI provider’s runner list or your self-hosted runner configuration. Pin explicit versions like
ubuntu-24.04for release builds and schedule the upgrade deliberately.Testing against end-of-life runtimes in the matrix.
Review the runtime versions in the matrix against the upstream release schedule at least twice a year. For Node.js, drop versions once they reach end of life and add the new LTS line.
Related Markdown Table Templates
Browse all 50 templatesCron Job Schedule Syntax Reference
Cheat sheet for 5-field crontab scheduling expressions, field ranges, special wildcard characters, and human frequency interpretations.
Environment Variables (.env) Matrix
Document required and optional environment keys, secret classifications, types, and staging vs production defaults.
Docker Container Ports & Volumes Matrix
Map container service names, host ports, guest ports, protocols, volume bindings, and persistence scopes.
CI/CD Pipeline Stages & Automation Gates: Frequently Asked Questions
What is a good default job timeout?
Roughly twice the job’s typical duration, rounded up. That is high enough to absorb slow runners and cold caches and low enough that a hung test is killed in minutes rather than after the six-hour GitHub Actions default.
Can a scheduled nightly job be a blocking gate?
Not for pull requests, because it does not run on them. A nightly scan can block releases if the release job checks its latest result, or it can open an issue on failure. Mark it No for merges and document its schedule with the cron syntax reference.
How should matrix builds appear in this table?
One row per job, with the matrix values in the runner column, such as Node 22 and 24. Branch rules, however, need each leg’s check name, so list those names in the job column or in a footnote.
Should the deploy job have a timeout too?
Yes, and it should be paired with a concurrency group so two deploys never run at once. A deploy that hangs while holding a lock or a half-applied migration is worse than one that fails fast and alerts someone.