GitHub Actions
Intermediate GitHub UI
Why this matters
Checks are the gatekeeper on every pull request, and when one fails the merge button locks. Usually the cause is your change and the fix takes a minute, if you can find it. This lesson is about reading the result; Section 14 is about the ideas and writing the file.
The vocabulary
| Word | Means |
|---|---|
| Workflow | An automated process defined in a YAML file, made of jobs |
| Event | What triggers it: a push, a pull request, a schedule, a manual run |
| Job | A set of steps that run together on one runner; jobs run in parallel unless they declare a dependency |
| Step | One command or one action inside a job |
| Action | A reusable step someone else wrote, such as actions/checkout |
| Runner | The machine that executes a job |
| Artifact | A file a job produces and keeps, such as a report or a built site |
Workflow files live in .github/workflows/, one file per workflow, and they are part of the repository, so you can read them without asking anyone.
Where you see it
| Place | Shows |
|---|---|
| The pull request's Conversation | A checks summary above the merge box |
| The pull request's Checks tab | Each job, its steps and its log |
| The repository's Actions tab | Every run, filterable by workflow, branch, actor and status |
| A commit | Its own status mark, linking to the run |
Statuses are success, failure, cancelled, skipped, queued and in progress. A check can also be neutral, which does not block a merge.
Reading a failure
Four steps, and the third is where people give up too early.
- Open the failing job, from the pull request's Checks tab or the Actions tab. The summary only tells you which job failed.
- Find the failed step. Steps are collapsible; the failed one is expanded and marked. Everything above it succeeded.
- Read upwards from the end of that step, not the last line of the log. The final line is often
Process completed with exit code 1, which says only that something failed. The useful line is above it and usually names a file and a line number. - Match it to your change. If it names a file you touched, it is yours. If not, check whether the same workflow fails on
mainbefore assuming you broke it.
A Markdown lint failure, the one a documentation contributor meets most, looks like this:
docs/getting-started.md:31 MD001/heading-increment Heading levels should only increment by one level at a time [Expected: h2; Actual: h3]
Error: Process completed with exit code 1File, line, rule, expectation. Fix that line, commit, push; the workflow runs again by itself.
Re-running
Re-run jobs offers all jobs or only the failed ones, and Re-run with debug logging adds verbose output. Re-running is right when the failure was infrastructure: a timeout, a runner problem, a network error fetching a dependency. It is wrong when the log names your file, because the same code fails the same way.
A job that fails intermittently on unchanged code is flaky and deserves an issue rather than a habit of re-running.
Reading a workflow file
name: CI
on:
push:
pull_request:
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: python -m unittest discover -s tests -v
lint-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npx --yes markdownlint-cli "**/*.md" --ignore node_modulesFive things to recognize:
onis the event list: this runs on every push and every pull request.jobsnames the jobs;testsandlint-docsrun in parallel.runs-onis the runner's operating system.usespulls in someone else's action, pinned to a version.runis a command. You can run these yourself, locally, before pushing, which is the best way to avoid red checks.
That last point is worth acting on: npx markdownlint-cli "**/*.md" takes ten seconds locally and catches what the workflow would catch ten minutes later.
Secrets and permissions, briefly
Workflows read secrets from Settings → Secrets and variables → Actions, referenced as ${{ secrets.NAME }}. GitHub redacts them from logs, but two facts matter to a contributor:
- Secrets are not passed to workflows triggered by a pull request from a fork, which is why a fork's checks sometimes skip a job.
- Anyone who can change a workflow file can make it print what it can read, which is why workflow changes attract careful review.
How to do it
There is no Git command for checks. What the terminal gives you is the ability to run the same commands first:
$ python3 -m unittest discover -s tests -v
$ npx --yes markdownlint-cli "**/*.md" --ignore node_modulesWith GitHub's gh tool, gh run list and gh run view --log-failed read the logs without a browser.
The GitHub Actions extension shows workflow runs and logs in the sidebar and validates workflow YAML as you edit it, which catches indentation errors before a push.
The Pull Requests tool window shows each check and links to its log. Workflow YAML gets schema completion in the Ultimate edition.
The same ideas with different words: a pipeline of stages and jobs defined in .gitlab-ci.yml, with the status shown on the merge request. See lesson 9.10.
- On the pull request, read the checks summary, then open Checks and select the failing job.
- Expand the failed step and read upwards from its end; use the log search box.
- Fix, commit, push; the workflow re-runs automatically.
- Re-run failed jobs only when the cause was infrastructure.
- Actions in the repository shows every run, including scheduled ones that nobody triggered.
Common mistakes
- Reading only the last line.
Process completed with exit code 1is the symptom. - Re-running a real failure. The same code fails the same way.
- Assuming red means you broke it. Check whether
mainis red too. - Not running the workflow's own commands locally. They are written down in the file.
- Pushing repeatedly to see whether it passes, which costs minutes and clutters the pull request.
Try it yourself
Goal: break a check on purpose and fix it from the log.
- On a branch in your practice repository, add a fourth-level heading directly under a second-level one in
docs/faq.md. - Commit, push, open a pull request.
- When the check fails, open Checks, expand the failed step, and find the line naming the file, line number and rule.
- Fix it, commit, push, and watch the check re-run.
- Before the next push, run the same command locally and confirm it reports the same thing.
Expected result: the log names docs/faq.md, a line number and MD001; after the fix the check passes; the local command agrees.
Show solution
Step 5 is the habit worth keeping. A workflow's run lines are the exact checks, so running them locally turns a ten-minute round trip into ten seconds. If a workflow needs secrets you do not have, run the parts that do not, which is usually the linting.
Check yourself
Key terms
Pipeline Continuous integration (CI) Continuous delivery / deployment (CD) Artifact Logs (program output)