Fatskills
Practice. Master. Repeat.
Study Guide: TECH **GitHub Actions Basics: Zero-Fluff CI/CD in YAML**
Source: https://www.fatskills.com/web-development/chapter/tech-github-actions-basics-zero-fluff-cicd-in-yaml

TECH **GitHub Actions Basics: Zero-Fluff CI/CD in YAML**

By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.

⏱️ ~7 min read

GitHub Actions Basics: Zero-Fluff CI/CD in YAML

Your hyper-practical guide to automating workflows, deployments, and tests—without the fluff.


1. What This Is & Why It Matters

GitHub Actions is GitHub’s built-in CI/CD (Continuous Integration/Continuous Deployment) engine. It lets you define automated workflows in YAML files that run when events happen in your repo (e.g., a git push, a pull request, or a scheduled cron job).

Why This Matters in Production

  • Without CI/CD: You manually test, build, and deploy code. This is slow, error-prone, and doesn’t scale. One bad git push can break production.
  • With CI/CD: Every code change triggers automated tests, builds, and deployments. You catch bugs early, deploy faster, and reduce human error.

Real-World Scenario

You’re a DevOps engineer at a startup. Your team merges 20+ pull requests daily. Without GitHub Actions: - A developer pushes broken code → production crashes → customers complain → you scramble to roll back.
- A security vulnerability slips through → you get hacked → compliance fines.

With GitHub Actions: - Every git push runs unit tests → if tests fail, the PR can’t merge.
- Every merge to main auto-deploys to staging → QA tests before production.
- Every night, a scheduled job runs security scans → vulnerabilities are caught early.

Superpower: You ship code faster, safer, and with less manual work.


2. Core Concepts & Components

Term Definition Production Insight
Workflow A YAML file (.github/workflows/*.yml) defining a CI/CD pipeline. Runs on GitHub’s servers. If you don’t version-control workflows, you lose auditability. Always commit .github/workflows/.
Event A trigger for a workflow (e.g., push, pull_request, schedule). Overusing push events can waste GitHub Actions minutes (costs money). Use pull_request for testing.
Job A set of steps that run on the same runner. Jobs can run in parallel or sequentially. If jobs depend on each other, use needs: job1 to enforce order.
Step An individual task in a job (e.g., run: npm test). Can be a shell command or an action. Steps run in order. If one fails, the job fails (unless you use continue-on-error: true).
Action A reusable unit of code (e.g., actions/checkout@v4). Can be from GitHub Marketplace or your own repo. Always pin actions to a specific version (e.g., @v4) to avoid breaking changes.
Runner A VM (Ubuntu, Windows, macOS) or self-hosted machine that executes workflows. GitHub-hosted runners have time limits (6h for free, 36h for paid). For long jobs, use self-hosted runners.
Environment A named target (e.g., staging, production) with secrets and protection rules. Use environments to enforce manual approvals before production deploys.
Secrets Encrypted variables (e.g., AWS_ACCESS_KEY_ID). Stored in repo settings. Never hardcode secrets in YAML. Use ${{ secrets.MY_SECRET }}.
Artifact A file (e.g., build output, logs) uploaded during a workflow. Use artifacts to pass data between jobs (e.g., test reports).
Matrix A way to run jobs with multiple OSes, languages, or versions (e.g., node: [14, 16, 18]). Useful for cross-platform testing, but can explode costs if overused.


3. Step-by-Step: Build Your First CI Pipeline

Goal: Create a workflow that: 1. Runs on every push to main.
2. Installs dependencies.
3. Runs tests.
4. Uploads test results as an artifact.

Prerequisites

  • A GitHub repo (public or private).
  • A project with tests (e.g., Node.js, Python, Go).
  • Basic YAML knowledge (indentation matters!).

Step 1: Create the Workflow File

  1. In your repo, create .github/workflows/ci.yml.
  2. Paste this template (adjust for your language):
name: CI Pipeline

on:
  push:
branches: [ "main" ] pull_request:
branches: [ "main" ] jobs: test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
- name: Upload test results
uses: actions/upload-artifact@v3
if: always() # Upload even if tests fail
with:
name: test-results
path: test-results/

Step 2: Commit and Push

git add .github/workflows/ci.yml
git commit -m "Add CI pipeline"
git push

Step 3: Verify the Workflow

  1. Go to your repo → Actions tab.
  2. Click on the latest workflow run.
  3. Check:
  4. ✅ All steps passed (green checkmarks).
  5. ✅ Test results artifact is uploaded (downloadable).

Step 4: Add a Badge to Your README

Add this to your README.md to show CI status:


![CI Pipeline](https://github.com/your-username/your-repo/actions/workflows/ci.yml/badge.svg)


4. ? Production-Ready Best Practices


Security

  • Never hardcode secrets. Use ${{ secrets.MY_SECRET }} and store secrets in Repo Settings → Secrets.
  • Restrict workflow permissions. Add permissions: to limit access (e.g., contents: read).
  • Use environments for deployments. Enforce manual approvals for production.

Cost Optimization

  • Avoid push triggers for every branch. Use pull_request to save minutes.
  • Cache dependencies. Use actions/cache@v3 to speed up builds.
  • Use self-hosted runners for long jobs. GitHub-hosted runners have time limits.

Reliability & Maintainability

  • Pin action versions. @v4 instead of @latest.
  • Use if: always() for cleanup steps. Ensures artifacts/logs are uploaded even if tests fail.
  • Tag workflows. Use name: and description: for clarity.

Observability

  • Add logging. Use echo "::debug::Debug message" for troubleshooting.
  • Upload artifacts. Store logs, test results, and build outputs.
  • Set up notifications. Use GitHub’s built-in alerts or Slack webhooks.


5. ⚠️ Common Mistakes & Traps

Mistake Symptom Fix/Prevention
Hardcoding secrets in YAML Secrets leak in logs or Git history. Use ${{ secrets.MY_SECRET }} and store in GitHub Secrets.
Using @latest for actions Workflow breaks when action updates. Pin to a version (e.g., @v4).
No needs: for dependent jobs Jobs run out of order. Use needs: job1 to enforce order.
Overusing push triggers Workflow runs on every branch, wasting minutes. Use pull_request for testing.
Not caching dependencies Every run installs dependencies from scratch (slow). Use actions/cache@v3.


6. ? Exam/Certification Focus


Typical Question Patterns

  1. "Which event triggers a workflow on a pull request?"
  2. pull_request
  3. push (triggers on commits, not PRs)

  4. "How do you run a job only if another job succeeds?"

  5. needs: job1
  6. depends_on: job1 (not valid in GitHub Actions)

  7. "Where do you store secrets for a workflow?"

  8. ✅ GitHub Secrets (Repo Settings → Secrets)
  9. ❌ In the YAML file (security risk)

  10. "How do you cache Node.js dependencies?"

  11. actions/cache@v3 with path: node_modules
  12. ❌ Manually running npm install in every job (slow)

Key Trap Distinctions

  • on: push vs on: pull_request
  • push: Runs on every commit to the branch.
  • pull_request: Runs only when a PR is opened/updated (saves minutes).

  • runs-on: ubuntu-latest vs self-hosted runners

  • GitHub-hosted: Free but time-limited (6h).
  • Self-hosted: No time limits but requires maintenance.


7. ? Hands-On Challenge

Challenge: Modify your CI pipeline to: 1. Run tests on Node.js 18 and 20 (matrix strategy).
2. Upload test results as an artifact only if tests fail.

Solution:


jobs:
  test:
strategy:
matrix:
node-version: [18, 20]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test
- uses: actions/upload-artifact@v3
if: failure() # Only upload if tests fail
with:
name: test-results-node-${{ matrix.node-version }}
path: test-results/

Why It Works:
- matrix runs the job for each Node.js version.
- if: failure() ensures artifacts are uploaded only on test failures.


8. ? Rapid-Reference Crib Sheet

Command/Concept Usage Notes
on: push Trigger on commits. ⚠️ Can waste minutes. Use pull_request for testing.
on: pull_request Trigger on PRs. Saves minutes vs push.
runs-on: ubuntu-latest GitHub-hosted runner. Free but time-limited (6h).
needs: job1 Run job only if job1 succeeds. Enforces job order.
${{ secrets.MY_SECRET }} Access a secret. Store in Repo Settings → Secrets.
actions/checkout@v4 Checkout repo code. Always needed as first step.
actions/cache@v3 Cache dependencies. Speeds up builds.
if: always() Run step even if previous steps fail. Useful for cleanup.
if: failure() Run step only if previous steps fail. Useful for error handling.
strategy.matrix Run job with multiple configs. E.g., node-version: [18, 20].
env: Set environment variables. E.g., env: NODE_ENV: test.


9. ? Where to Go Next

  1. GitHub Actions Docs – Official reference.
  2. GitHub Actions Marketplace – Pre-built actions.
  3. Awesome Actions – Curated list of useful actions.
  4. GitHub Actions Cheat Sheet – Quick reference.

Final Tip

Start small. Automate one thing (e.g., tests on PRs). Then expand (e.g., deploy to staging on merge). GitHub Actions scales with your needs—no need to over-engineer Day 1. ?



ADVERTISEMENT