What You'll Build
You will create the first GitHub Actions workflow for CricketPulse — a live cricket scores and statistics API. The workflow will be triggered on push to main and on all pull requests, run two jobs in parallel (a build-info job that echoes pipeline context and a test job that runs a trivial validation script), and produce visible output in the GitHub Actions UI. This exercise is deliberately simple — the focus is entirely on workflow structure, YAML syntax, trigger configuration, and reading the Actions interface. By the end, you will be able to read a workflow run log, understand the job timeline, and know where status checks appear on pull requests. These navigation skills are the foundation for every subsequent debugging exercise in the course.
Prerequisites
- A GitHub account with the ability to create public repositories — the Actions free tier provides 2,000 minutes per month for public repos and 500 MB storage.
- Git installed locally and basic Git knowledge: `git clone`, `git add`, `git commit`, `git push`.
- A text editor with YAML support (VS Code with the GitHub Actions extension is recommended — it provides schema validation and autocomplete for workflow files).
- Familiarity with GitHub Actions concepts from Lessons 1–3: workflows, jobs, steps, triggers, and the `github` context.
- A GitHub repository to work in — either create a new one named `cricketpulse` or fork the course starter repository.
Setup & Project Structure
Start by creating the repository structure and the required directory for GitHub Actions workflows. The `.github/workflows/` directory is a GitHub convention — Actions only recognises workflow files in this exact path. You will also create a minimal Node.js project with a `package.json` and a simple test script so the workflow has something meaningful to execute. The entire setup takes under two minutes and produces a repository structure that mirrors what you will use throughout the rest of the course.
# Terminal commands — run these to set up the project
# Create and enter the project directory
mkdir cricketpulse && cd cricketpulse
git init
git remote add origin https://github.com/YOUR_USERNAME/cricketpulse.git
# Create the workflows directory
mkdir -p .github/workflows
# Create a minimal package.json
cat > package.json << 'EOF'
{
"name": "cricketpulse",
"version": "1.0.0",
"description": "Live cricket scores and statistics API",
"scripts": {
"test": "node scripts/validate.js",
"build": "echo 'CricketPulse build complete'"
}
}
EOF
# Create a scripts directory and a simple validation script
mkdir scripts
cat > scripts/validate.js << 'EOF'
// Trivial validation — confirms Node.js is running and exits cleanly
const data = {
matchId: 'IPL-2024-CSK-MI-042',
venue: 'Wankhede Stadium, Mumbai',
battingTeam: 'Mumbai Indians',
score: { runs: 187, wickets: 4, overs: 20 },
topScorer: { name: 'Rohit Sharma', runs: 68, balls: 42 }
};
console.log('CricketPulse data validation starting...');
console.log(`Match: ${data.matchId}`);
console.log(`Score: ${data.score.runs}/${data.score.wickets} in ${data.score.overs} overs`);
console.log(`Top scorer: ${data.topScorer.name} — ${data.topScorer.runs}(${data.topScorer.balls})`);
// Validate required fields
const required = ['matchId', 'venue', 'battingTeam', 'score', 'topScorer'];
required.forEach(field => {
if (!data[field]) throw new Error(`Missing required field: ${field}`);
});
console.log('\n✅ All validations passed. CricketPulse data structure is correct.');
process.exit(0);
EOF
echo "Project structure created successfully"Step 1 — Foundation
Create the workflow file. This step introduces the core YAML structure: the `name:` field for the workflow display name, the `on:` trigger block with both `push` and `pull_request` triggers, and the `jobs:` block. The first job — `pipeline-info` — will run a set of `echo` commands that read from the `github` context, producing visible output in the Actions log that demonstrates how context values are resolved at runtime. This job has no external dependencies: no `npm install`, no test frameworks. It simply proves that the runner started, the workflow YAML parsed correctly, and context values are accessible.
# File: .github/workflows/cricketpulse-ci.yml
# Step 1: Workflow skeleton with pipeline-info job
name: CricketPulse CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
pipeline-info:
name: Pipeline Context Information
runs-on: ubuntu-latest
steps:
- name: Print workflow context
run: |
echo "=== CricketPulse Pipeline Context ==="
echo "Workflow: ${{ github.workflow }}"
echo "Run number: ${{ github.run_number }}"
echo "Triggered by: ${{ github.event_name }}"
echo "Actor: ${{ github.actor }}"
echo "Branch: ${{ github.ref_name }}"
echo "Commit SHA: ${{ github.sha }}"
echo "Repository: ${{ github.repository }}"
echo "Runner OS: ${{ runner.os }}"
echo "======================================"Step 2 — Core Logic
Add the test job that runs the validation script. This job runs in parallel with `pipeline-info` — both start immediately when the workflow triggers because neither declares a `needs:` dependency. The test job uses the `actions/checkout` and `actions/setup-node` marketplace actions to prepare the environment before executing the validation script. This step demonstrates how reusable actions eliminate boilerplate and how to pass configuration to them via the `with:` block.
# File: .github/workflows/cricketpulse-ci.yml
# Step 2: Add test job running in parallel with pipeline-info
name: CricketPulse CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
pipeline-info:
name: Pipeline Context Information
runs-on: ubuntu-latest
steps:
- name: Print workflow context
run: |
echo "=== CricketPulse Pipeline Context ==="
echo "Workflow: ${{ github.workflow }}"
echo "Run number: ${{ github.run_number }}"
echo "Triggered by: ${{ github.event_name }}"
echo "Actor: ${{ github.actor }}"
echo "Branch: ${{ github.ref_name }}"
echo "Commit SHA: ${{ github.sha }}"
echo "Repository: ${{ github.repository }}"
echo "Runner OS: ${{ runner.os }}"
echo "======================================"
test:
name: Validate CricketPulse Data
runs-on: ubuntu-latest
# No 'needs:' — runs in parallel with pipeline-info
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js 20
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Run CricketPulse validation script
run: node scripts/validate.js
- name: Confirm successful validation
run: |
echo "✅ CricketPulse validation passed on commit ${{ github.sha }}"
echo " Branch: ${{ github.ref_name }}"
echo " Run: #${{ github.run_number }}"Step 3 — Integration & Enhancement
Add a third job — `summary` — that depends on both previous jobs and writes a structured summary to the GitHub Actions job summary. Job summaries are a GitHub Actions feature that allows workflows to post formatted Markdown visible in the workflow run summary page. This step demonstrates `needs:` for sequential execution, the `always()` status check function for running even when upstream jobs fail, and writing to `$GITHUB_STEP_SUMMARY` — a useful pattern for surfacing important information without burying it in verbose log output.
# File: .github/workflows/cricketpulse-ci.yml
# Step 3: Final complete workflow with summary job
name: CricketPulse CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
pipeline-info:
name: Pipeline Context Information
runs-on: ubuntu-latest
steps:
- name: Print workflow context
run: |
echo "Workflow: ${{ github.workflow }} | Run: #${{ github.run_number }}"
echo "Triggered by: ${{ github.event_name }} on ${{ github.ref_name }}"
echo "Actor: ${{ github.actor }} | SHA: ${{ github.sha }}"
test:
name: Validate CricketPulse Data
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js 20
uses: actions/setup-node@v4
with: { node-version: '20' }
- name: Run CricketPulse validation script
run: node scripts/validate.js
summary:
name: Workflow Summary
runs-on: ubuntu-latest
needs: [pipeline-info, test] # Runs after BOTH jobs complete
if: always() # Runs even if pipeline-info or test failed
steps:
- name: Write job summary
run: |
cat >> $GITHUB_STEP_SUMMARY << 'SUMMARY'
## 🏏 CricketPulse CI Summary
| Property | Value |
|----------|-------|
| **Workflow** | ${{ github.workflow }} |
| **Run number** | #${{ github.run_number }} |
| **Trigger** | ${{ github.event_name }} |
| **Branch** | ${{ github.ref_name }} |
| **Actor** | ${{ github.actor }} |
| **Commit** | `${{ github.sha }}` |
### Job Results
- Pipeline Info: ${{ needs.pipeline-info.result }}
- Validation Tests: ${{ needs.test.result }}
SUMMARYStep 4 — Testing & Verification
Push the completed workflow to GitHub and verify it triggers correctly. Then introduce a deliberate failure to observe how GitHub Actions surfaces the error in the Actions UI and on the pull request check. This failure-observation step is critical — knowing how failures look in the interface is as important as knowing how successes look, because you will spend significant time debugging pipelines in your career.
# Terminal: push the workflow and observe it run
# Commit and push the workflow file
git add .github/workflows/cricketpulse-ci.yml scripts/validate.js package.json
git commit -m "feat: add initial CricketPulse CI workflow"
git push origin main
# GitHub Actions will trigger immediately — navigate to:
# https://github.com/YOUR_USERNAME/cricketpulse/actions
# Expected: Three jobs visible in the workflow run:
# ✅ Pipeline Context Information
# ✅ Validate CricketPulse Data
# ✅ Workflow Summary
# --- DELIBERATE FAILURE TEST ---
# Edit scripts/validate.js: add this line near the end:
# throw new Error('Simulated pipeline failure for Lesson 4 exercise');
git add scripts/validate.js
git commit -m "test: simulate pipeline failure for learning exercise"
git push origin main
# Expected output in Actions:
# ✅ Pipeline Context Information (unaffected — runs in parallel)
# ❌ Validate CricketPulse Data (fails with error message visible in log)
# ⚠️ Workflow Summary (runs due to 'if: always()', shows failed status)
# Navigate to the failed job in the Actions UI:
# 1. Click the red ❌ on 'Validate CricketPulse Data'
# 2. Expand the 'Run CricketPulse validation script' step
# 3. Observe the error message and exit code
# 4. Note the red X on the commit in the repository's commit list
# Restore the passing state:
# Remove the throw line and push again
git add scripts/validate.js
git commit -m "fix: remove simulated failure"
git push origin mainWarning: If your workflow shows 'No workflow runs' in the Actions tab after pushing, check two things. First, verify the file is in `.github/workflows/` (the dot prefix is easy to miss). Second, confirm the branch name matches your `on: push: branches:` list — if your repository default branch is `master` and you listed `main`, the trigger will never fire. Run `git branch` to check your current branch name and update the workflow accordingly.
Extension Challenge: Add a fourth job to the workflow that only runs when the trigger is a `pull_request` event. This job should post the PR number, the head branch name, and the target branch to the step log using `github.event.pull_request.number`, `github.head_ref`, and `github.base_ref`. Create a branch, push a commit, and open a pull request to observe this job appear exclusively on PR-triggered runs.
- GitHub Actions workflow files must be in `.github/workflows/` with a `.yml` or `.yaml` extension — any other path is ignored by GitHub.
- Jobs with no `needs:` declaration run in parallel immediately; the `summary` job's `needs: [pipeline-info, test]` ensures it only starts after both predecessors complete.
- The `if: always()` status function overrides default failure-halt behaviour, allowing jobs like `summary` to run even when upstream jobs fail — essential for post-failure reporting and cleanup.
- Context values like `${{ github.sha }}` and `${{ github.actor }}` are resolved server-side before the runner executes, making them safe and consistent across all steps.
- Writing to `$GITHUB_STEP_SUMMARY` produces formatted Markdown visible in the workflow run's summary page — a cleaner alternative to burying important information in verbose step logs.
- Observing how a pipeline failure looks in the Actions UI — red job badges, error step expansion, commit status indicators — is as important as understanding successful runs.