← All 87 books ghactions, one workflow piece per page Get the full edition · £10
One workflow piece per page

ghactions, one workflow piece per page

Twenty-nine pieces for your first CI: why pushed workflows silently refuse to run, the .github/workflows file itself, push and pull_request triggers and what each one sees, branch filters, cron in UTC on the default branch, the manual run button, forks opting in, jobs and steps and needs ordering, runs-on machines, checkout and run and uses, secrets and the GITHUB_TOKEN dial, cache keys, artifacts between machines, the matrix, if conditions, concurrency cancels, timeouts, contexts, environments, re-running failed jobs, and the six-question checklist for the run that never started.


Steve Hodgkiss 7 pieces

A diagram, the mechanism, and one thing to do this week. That's a page.

ghactions, one workflow piece per page

Twenty-nine pieces for your first CI: why pushed workflows silently refuse to run, the .github/workflows file itself, push and pull_request triggers and what each one sees, branch filters, cron in UTC on the default branch, the manual run button, forks opting in, jobs and steps and needs ordering, runs-on machines, checkout and run and uses, secrets and the GITHUB_TOKEN dial, cache keys, artifacts between machines, the matrix, if conditions, concurrency cancels, timeouts, contexts, environments, re-running failed jobs, and the six-question checklist for the run that never started.


Set in Space Grotesk, Inter and JetBrains Mono (SIL Open Font License).

General information only. Every fact in this book is as the official GitHub documentation states it, fetched and read during this build: events that trigger workflows and workflow syntax for GitHub Actions (docs.github.com/en/actions), including the push, pull_request, schedule and workflow_dispatch events, the jobs, steps, uses, run, needs, if, matrix, concurrency, permissions and timeout-minutes keys; plus the GitHub docs on variables and secrets, caching with actions/cache, artifacts, and using environments for deployment. GitHub Actions evolves: check the current documentation for behaviour that matters to you. Demand evidence from live beginner threads, reconfirmed at dispatch; no facts are sourced from Reddit. An independent guide, not affiliated with or endorsed by GitHub or Microsoft.

Your purchase is for personal use only. You do not have redistribution rights: please do not share, resell, or republish this book or its pages.

© 2026 Steve Hodgkiss. All rights reserved. Personal use only; no redistribution rights.

Edition 1.0 · stevehodgkiss.net

Contents

Contents


Part 1 · Why didn't it run4
One YAML file5
The push trigger6
Cron needs main7
Forks opt in8
Part 2 · The skeleton
Jobs and steps9
Part 3 · Pieces
Secrets, masked10
Part 4 · Debugging
The run checklist11
Part 1 of 4
the silent no-show
1

Why didn't it run

The question every beginner arrives with: a pushed workflow that never started. The file's home and shape, the push trigger, branch filters, cron's default-branch rule, the manual button, forks opting in.


In this part
  1. 01One YAML file
  2. 02The push trigger
  3. 03Cron needs main
  4. 04Forks opt in

Per GitHub Docs, Workflow syntax for GitHub Actions: workflow files use YAML and must have a .yml or .yaml extension; they must be stored in the .github/workflows directory of the repository. The workflow name shows under the Actions tab; if name is omitted, GitHub displays the workflow file path relative to the repository root.

run it anyway · No. 01
First file

One YAML file

The workflow lives in a folder

where the workflow livesyour repository.github/workflowsci.ymlpushthe workflowshows in theActions tabno name: thefile path shows.yml or .yaml, in .github/workflows, on the branch that triggers

A workflow is one YAML file in one specific place: .github/workflows/ at the repository root, with a .yml or .yaml extension. Nothing outside that folder ever runs. The tab and spaces rule bites here: YAML forbids tabs for indentation, so spaces only.

Give it a name: too. Omit it and the Actions tab shows the file path instead of a friendly title, which is why so many beginners see a filename where a workflow name should be.

One folder, one file, one name: that is the whole unit.

DO THIS WEEK

Create .github/workflows/ci.yml in one of your repositories today with only name: CI at the top. Commit it to the default branch and find it listed under the Actions tab, showing no runs yet.

Per GitHub Docs, Events that trigger workflows (push entry): the push event runs your workflow when you push a commit or tag, or when you create a repository from a template; the SHA in the run is the tip commit pushed to the ref. The classic beginner failure, per the recurring r/github threads at dispatch: a workflow file that exists only on an unpushed or non-triggering branch never fires.

run it anyway · No. 02
Why didn't it run

The push trigger

Runs when you push a commit

the push event, end to endwhat you dida commitwhat GitHub doesa run starts,on the pushed tipsilentno-show:file neverpushedthe file exists only on your laptopthe file sits on a branch the trigger never seespush fires only on what was actually pushed, to a ref that exists

on: push runs the workflow every time a commit is pushed to any branch. It is the default heartbeat of CI, and it answers the most common beginner question, why did nothing run, with a checklist: the file must be committed and pushed, and it must sit on the branch that was pushed. A workflow file that only exists on your laptop does nothing.

The run uses the pushed commit as its snapshot, so what the workflow tests is exactly what you pushed.

Push trigger, pushed file. No push, no run.

DO THIS WEEK

Add on: push to your ci.yml, commit a trivial change, and watch the Actions tab start a run the moment the push lands. If nothing starts, run git status before touching the YAML.

Per GitHub Docs, Events that trigger workflows (schedule): scheduled workflows run on the latest commit on the default branch only; POSIX cron syntax in UTC by default; the shortest interval is five minutes; high load times, especially at the start of the hour, can delay scheduled runs. Per the dispatch r/github threads: cron jobs that only exist on a feature branch never fire, by design.

run it anyway · No. 03
Why didn't it run

Cron needs main

Schedules live on the default branch

the schedule trigger has two hard rulesUTC onlyschedule: - cron: '17 5 * * 1'05:17 UTC, Mondaysmainruns on main'slatest commitfeaturenever firesqueues are busiest on the hour: pick odd minutes, expect delayscron speaks UTC and lives on the default branch, by design

schedule: with a cron line is the timed trigger, and it carries two non-negotiable rules: the cron is UTC, and the scheduled workflow runs only on the latest commit of the default branch. A cron job merged into a feature branch never fires, and that is by design.

Two habits: avoid the top of the hour, when everyone's jobs queue at once and runs start late; and remember 17 5 * * 1 means 05:17 UTC on Mondays, not your local Monday.

Cron reads UTC, lives on main, and waits in queues like everything else.

DO THIS WEEK

Convert a time you actually want a job to run, say 9am your local time, into UTC and write the cron line for it. Check it against your clock's timezone offset and park the line in a note for the schedule page's build.

Per GitHub Docs (usage and billing, and the dispatch threads on forked repos): when you first visit the Actions tab of a fork, GitHub asks you to enable workflows before any run starts; the classic dispatch thread pattern is a pushed project whose build silently never starts until the Actions tab is visited and workflows enabled.

run it anyway · No. 04
Why didn't it run

Forks opt in

Enable Actions after forking

a fork runs nothing until you say sothe forktwo remotes, one historythe Actions tabI understand my workflows,go ahead and enable themone click: enable workflowspushes before the click never ran; pushes after behave normally

Fork a repository and GitHub deliberately runs nothing: the Actions tab shows an enable-workflows confirmation, and until you click it, every push sits silent. The project's build not starting after forking is almost always this, not your YAML.

Visit the tab, read the prompt, enable, and the next push behaves normally. It exists so a fork does not burn compute or run untrusted configurations the moment it is copied.

Forked? The Actions tab is your first stop, not your last resort.

DO THIS WEEK

If you have a fork whose CI has never once run, open its Actions tab today and either enable workflows or confirm the prompt is gone. Note the exact wording of the prompt while you are there.

Per GitHub Docs, Workflow syntax (jobs): a workflow run is made up of one or more jobs, each of which runs on a fresh runner virtual machine by default and in parallel with the others unless needs creates dependency; each job has steps that can run shell commands or actions.

run it anyway · No. 05
The skeleton

Jobs and steps

Jobs are machines, steps are lines

the workflow's skeletonjobs: build: runs-on: ubuntu-latest steps: - run: make testjob one: a fresh VM,steps in order, files sharedjob two: its own VM,sees nothing of job onejobs are machines in parallel; steps are lines in order on one machine

Under jobs, each job id names a block that gets its own fresh virtual machine. Jobs run in parallel by default. Inside a job, steps run in order on that one machine, sharing files through the workspace.

Two jobs mean two clean machines that see nothing of each other; two steps mean one machine doing two things back to back. Choose by what needs to share files, not by what looks organised.

Job: a machine. Step: a line on that machine.

DO THIS WEEK

Split your ci.yml into a job with two steps: the first prints the runner's operating system, the second lists the workspace files. Confirm both steps share one machine by matching the workspace listing.

Per GitHub Docs (using secrets in GitHub Actions and contexts guidance): secrets are stored at repository or organization level, referenced with the secrets context, exposed to steps as environment variables; pull requests from forks do not get secrets; the GITHUB_TOKEN is automatically available.

run it anyway · No. 06
Pieces

Secrets, masked

Keys never touch the log

secrets travel maskedsettingssecrets andvariables, actionsenv: TOKEN: ${{ secrets.API_KEY }}****stars in every logpull requests from forks receive no secrets at all, everkeys live in settings, reach steps as variables, print as stars

Anything a step needs that must not be printed, an API key, a deploy token, lives as a secret under the repository's settings, and reaches steps through the secrets context into an environment variable. Values that match a secret appear as stars in every log.

The boundary: pull requests from forks receive no secrets, so an outside contribution cannot print your keys. A step that needs secrets and must run on fork PRs is a design error, not a YAML one.

Secrets go in settings, not files; forks get nothing.

DO THIS WEEK

Add one real secret to a repository you own today, print it in a step, and confirm the log shows stars. Then delete the test step; the habit is knowing the mask works.

Composite of the dispatch threads' recurring checklist: the workflow file must be pushed, on the triggering branch, workflows enabled on forks, cron on the default branch in UTC; plus per GitHub Docs, workflow_dispatch for manual testing. This page is the whole book as one checklist.

run it anyway · No. 07
The tally

The run checklist

Why didn't it run

when nothing runs, ask in this orderthe six1 was the file pushed at all?2 is it on the triggering branch?3 is the cron job on the default branch?4 are workflows enabled (forks)?5 does the branch filter match?6 is the event the one you think?in the threads behind this book, the answer was on this page nearly every timeall six pass and still nothing runs? now, and only now, open the YAML

Almost every silent workflow reduces to six questions. Was the file pushed at all? Is it on the branch that triggers? Is cron on the default branch? Are workflows enabled in a fork? Does the branch filter actually match? Is the event the one you think fired?

Work down the list before touching the YAML. In the threads that produced this book, the answer was on this page nearly every time, and the workflow was fine all along.

Six questions, in order. That is the whole checklist.

DO THIS WEEK

Bookmark or screenshot this checklist and use it on the next silent run you meet. If all six pass and nothing runs, then, and only then, open the YAML.

Index

Index


Cron needs main7
Forks opt in8
Jobs and steps9
One YAML file5
Secrets, masked10
The push trigger6
The run checklist11