GitHub Actions Tutorial — Getting Started Exercises

2 minute read

Practice Exercises — Getting Started

Test your understanding of workflow creation and execution with these hands-on exercises.


Exercise 1 — Hello World Workflow

Task: Create a workflow file that:

  1. Triggers on push to the main branch
  2. Runs on ubuntu-latest
  3. Has three steps: (a) prints “Hello World”, (b) prints the current date, (c) lists files in the current directory

Push it and verify it runs in the Actions tab.

Show Solution

Create .github/workflows/hello.yml:


name: Hello World

on:
  push:
    branches: [main]

jobs:
  greet:
    runs-on: ubuntu-latest
    steps:
      - name: Say Hello
        run: echo "Hello World"

      - name: Show Date
        run: date

      - name: List Files
        run: ls -la

Push and check the Actions tab. The “List Files” step will show the runner’s default working directory (no repo files until you use actions/checkout).


Exercise 2 — Checkout and Build

Task: Create a workflow that:

  1. Triggers on push to main
  2. Checks out the repository code
  3. Creates a file called build-output.txt with the text “Build completed at {date}”
  4. Lists the repository contents to verify
Show Solution

name: Build

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Build
        run: echo "Build completed at $(date)" > build-output.txt

      - name: Verify
        run: |
          cat build-output.txt
          ls -la

Now the “Verify” step will show your repository files plus the newly created build-output.txt.


Exercise 3 — Manual Trigger with Inputs

Task: Create a workflow that:

  1. Can be triggered manually with workflow_dispatch
  2. Accepts two inputs: name (string, required) and greeting (choice: “hello” or “goodbye”)
  3. Prints a message combining both inputs

Trigger it from the Actions tab with different input values.

Show Solution

name: Greet User

on:
  workflow_dispatch:
    inputs:
      name:
        description: 'Your name'
        required: true
        type: string
      greeting:
        description: 'Greeting type'
        required: true
        default: 'hello'
        type: choice
        options:
          - hello
          - goodbye

jobs:
  greet:
    runs-on: ubuntu-latest
    steps:
      - name: Greet
        run: echo "${{ github.event.inputs.greeting }}, ${{ github.event.inputs.name }}!"

After pushing to main, go to Actions → “Greet User” → “Run workflow”. Fill in the inputs and click “Run workflow”.


Exercise 4 — Add a Status Badge

Task:

  1. Create a CI workflow that runs echo "All tests passed" on push to main
  2. Add a status badge for this workflow to your README.md
  3. Verify the badge shows “passing” after a successful run
Show Solution

Create .github/workflows/ci.yml:


name: CI

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: echo "All tests passed"

Add to README.md:


[![CI](https://github.com/YOUR_USER/YOUR_REPO/actions/workflows/ci.yml/badge.svg)](https://github.com/YOUR_USER/YOUR_REPO/actions/workflows/ci.yml)

Replace YOUR_USER and YOUR_REPO with your actual GitHub username and repository name.


Exercise 5 — Multi-Job Workflow

Task: Create a workflow with three jobs:

  1. lint — runs echo "Linting..."
  2. test — runs echo "Testing..." (must wait for lint)
  3. build — runs echo "Building..." (must wait for both lint and test)

Draw the expected execution order, then verify in the Actions tab.

Show Solution

name: Multi-Job Pipeline

on:
  push:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Linting..."

  test:
    runs-on: ubuntu-latest
    needs: lint
    steps:
      - run: echo "Testing..."

  build:
    runs-on: ubuntu-latest
    needs: [lint, test]
    steps:
      - run: echo "Building..."

Execution order:

┌──────┐
│ lint │
└──┬───┘
   │
┌──▼───┐
│ test │
└──┬───┘
   │
┌──▼────┐
│ build │
└───────┘

In the Actions tab, you’ll see lint run first, then test, then build. Since build needs both lint and test, and test already needs lint, the chain is fully sequential.


← Back to: Chapter 2: Getting Started

Next Chapter: Chapter 3: Triggers & Events →

Updated: