End-to-End QA Scenario
GitHub Actions Commands — Beginner's Reference
A friendly tour of the GitHub Actions building blocks: workflows, jobs, steps, runners, triggers, secrets, matrices, caching, artifacts and the most-used `run:` and `gh` CLI commands.
Architecture
.github/workflows/ci.yml
│
▼
on: push / pull_request / schedule / workflow_dispatch
│
▼
jobs:
build: ◄── one job = one runner VM (ubuntu-latest)
steps:
- uses: actions/checkout@v4 (pull repo code)
- uses: actions/setup-node@v4 (install toolchain)
- run: npm ci (shell command)
- run: npm test
- uses: actions/upload-artifact@v4 (save files for later)
│
▼
secrets.* / vars.* env: matrix: needs: if:Workflow steps
- 1
Where workflows live
Every workflow is a YAML file inside `.github/workflows/`. File name is free (e.g. `ci.yml`, `release.yml`), but it MUST end in `.yml` or `.yaml`. GitHub auto-discovers them — no registration step.
- 2
Minimal workflow skeleton
```yaml name: CI on: [push, pull_request] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: echo "Hello $GITHUB_ACTOR" ``` `name` shows in the Actions tab. `on` is the trigger. `runs-on` picks the runner image. `steps` runs top-to-bottom.
- 3
Triggers (`on:`) — the common ones
• `push` — every commit pushed to any branch. • `push: { branches: [main] }` — only main. • `pull_request` — on PR open/sync/reopen. • `schedule: - cron: '0 2 * * *'` — nightly at 02:00 UTC. • `workflow_dispatch` — manual button in the UI (great for beginners testing). • `release: { types: [published] }` — when you publish a GitHub Release.
- 4
`uses:` vs `run:` — the two kinds of steps
`uses:` calls a reusable Action from the Marketplace (`owner/repo@version`). `run:` executes a shell command on the runner. Pin Actions to a major version (`@v4`) for stability, or a commit SHA for max security. ```yaml - uses: actions/setup-python@v5 with: python-version: '3.12' - run: | python -m pip install -r requirements.txt pytest -q ```
- 5
The 8 Actions you'll use 90% of the time
• `actions/checkout@v4` — clone your repo into the runner. • `actions/setup-node@v4` / `setup-python@v5` / `setup-java@v4` / `setup-go@v5` — install a language toolchain. • `actions/cache@v4` — cache `node_modules`, `~/.m2`, pip wheels, etc. • `actions/upload-artifact@v4` & `actions/download-artifact@v4` — pass files between jobs or download from the UI. • `actions/github-script@v7` — run JS against the GitHub API inline. • `docker/login-action@v3` + `docker/build-push-action@v6` — build & push images.
- 6
Secrets, variables and environment
Add secrets in **Repo → Settings → Secrets and variables → Actions**. Use them as `${{ secrets.MY_TOKEN }}`. Non-sensitive values go under `vars` (`${{ vars.REGION }}`). Expose them to a step via `env:`: ```yaml - run: ./deploy.sh env: AWS_REGION: ${{ vars.REGION }} DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} ``` Secrets are auto-masked in logs. Never `echo` them.
- 7
Matrix builds — run the same job many ways
```yaml jobs: test: strategy: fail-fast: false matrix: node: [18, 20, 22] os: [ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: ${{ matrix.node }} } - run: npm test ``` This runs 6 parallel jobs (3 Node × 2 OS).
- 8
Job ordering with `needs:` and conditions with `if:`
`needs:` makes a job wait for another. `if:` skips a job/step when a condition is false. ```yaml jobs: build: { runs-on: ubuntu-latest, steps: [...] } test: { needs: build, runs-on: ubuntu-latest, steps: [...] } deploy: needs: test if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: [...] ```
- 9
Caching to speed up runs
```yaml - uses: actions/cache@v4 with: path: ~/.npm key: npm-${{ hashFiles('**/package-lock.json') }} restore-keys: npm- ``` Most `setup-*` actions also accept `cache: 'npm' | 'pip' | 'gradle'` to enable this with one line.
- 10
Artifacts — save & share files
```yaml - uses: actions/upload-artifact@v4 if: always() # upload even on failure with: name: playwright-report path: playwright-report/ retention-days: 14 ``` Download later in another job with `actions/download-artifact@v4`, or from the run's summary page in the UI.
- 11
Useful built-in expressions & contexts
• `${{ github.actor }}` — who triggered the run. • `${{ github.sha }}` / `${{ github.ref_name }}` — commit & branch. • `${{ github.event_name }}` — `push`, `pull_request`, etc. • `${{ runner.os }}` — `Linux` / `Windows` / `macOS`. • `${{ job.status }}` — `success` / `failure` / `cancelled`. • Step outputs: write `echo "key=value" >> $GITHUB_OUTPUT` then read `${{ steps.<id>.outputs.key }}`. • Env from a step: `echo "VERSION=1.2.3" >> $GITHUB_ENV`.
- 12
The `gh` CLI — drive Actions from your terminal
GitHub's official CLI (`brew install gh` or `winget install GitHub.cli`) talks to Actions over the API. Login once with `gh auth login`. • `gh workflow list` — list workflows. • `gh workflow run ci.yml -f environment=staging` — trigger a `workflow_dispatch` run with inputs. • `gh run list --workflow=ci.yml --limit 5` — recent runs. • `gh run watch` — live-tail the latest run. • `gh run view <run-id> --log` — full log; add `--log-failed` for only red steps. • `gh run rerun <run-id> --failed` — re-run only the failed jobs. • `gh run download <run-id> -n playwright-report` — download an artifact. • `gh secret set DEPLOY_KEY < key.pem` — upload a secret without opening the UI.
- 13
Local debugging tips
• Add `ACTIONS_STEP_DEBUG: true` as a repo secret to get verbose logs. • Use `act` (https://github.com/nektos/act) to run workflows locally in Docker — great for fast iteration before pushing. • Start with `workflow_dispatch` so you can re-run on demand from the Actions tab while learning.
- 14
First real workflow — Node + tests + artifact
```yaml name: CI on: pull_request: push: { branches: [main] } jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 cache: 'npm' - run: npm ci - run: npm test -- --reporter=junit --outputFile=results.xml - uses: actions/upload-artifact@v4 if: always() with: name: junit path: results.xml ``` Commit this as `.github/workflows/ci.yml`, push, and watch it run.
Key takeaways
- A workflow is just YAML in `.github/workflows/` — start with `workflow_dispatch` so you can press a button to run it.
- `uses:` pulls in reusable Actions; `run:` is plain shell. Pin Actions to `@vMAJOR` for safety.
- Secrets live in repo settings and are referenced as `${{ secrets.NAME }}` — never echo them.
- `matrix`, `needs`, `if`, `cache` and `upload-artifact` cover most real-world pipelines.
- Install the `gh` CLI early — `gh run watch` and `gh run view --log-failed` make debugging dramatically faster.
