Git Course 0%

GitHub Actions

Intermediate GitHub UI ≈ 12 min

What you will learn

  • What a workflow, event, job, step, action and runner are
  • How to read a failing check and find the real error
  • Enough workflow YAML to recognize what is being run

After this lesson you can

  • I can diagnose a red check on my own pull request and fix the common causes

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.

  1. Open the failing job, from the pull request's Checks tab or the Actions tab. The summary only tells you which job failed.
  2. Find the failed step. Steps are collapsible; the failed one is expanded and marked. Everything above it succeeded.
  3. 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.
  4. Match it to your change. If it names a file you touched, it is yours. If not, check whether the same workflow fails on main before assuming you broke it.

A Markdown lint failure, the one a documentation contributor meets most, looks like this:

Text
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 1

File, 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

.github/workflows/ci.yml
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_modules

Five things to recognize:

  • on is the event list: this runs on every push and every pull request.
  • jobs names the jobs; tests and lint-docs run in parallel.
  • runs-on is the runner's operating system.
  • uses pulls in someone else's action, pinned to a version.
  • run is 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:

Terminal
$ python3 -m unittest discover -s tests -v
$ npx --yes markdownlint-cli "**/*.md" --ignore node_modules

With GitHub's gh tool, gh run list and gh run view --log-failed read the logs without a browser.

Common mistakes

  • Reading only the last line. Process completed with exit code 1 is the symptom.
  • Re-running a real failure. The same code fails the same way.
  • Assuming red means you broke it. Check whether main is 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.

  1. On a branch in your practice repository, add a fourth-level heading directly under a second-level one in docs/faq.md.
  2. Commit, push, open a pull request.
  3. When the check fails, open Checks, expand the failed step, and find the line naming the file, line number and rule.
  4. Fix it, commit, push, and watch the check re-run.
  5. 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

1. A step's log ends with Process completed with exit code 1. What should you read?
2. When is re-running a failed job the right response?
3. Where is the definition of what a check actually runs?

Key terms

Pipeline Continuous integration (CI) Continuous delivery / deployment (CD) Artifact Logs (program output)