Git & GitHub

GitHub Actions Basics

13 min Lesson 23 of 35

GitHub Actions Basics

GitHub Actions is a powerful automation platform that allows you to build, test, and deploy your code directly from GitHub. It enables continuous integration and continuous deployment (CI/CD) workflows without leaving your repository.

What are GitHub Actions?

GitHub Actions automate tasks in your software development lifecycle. You can use them to run tests, deploy applications, send notifications, and much more - all triggered by events in your repository.

Key Benefit: GitHub Actions is free for public repositories with unlimited minutes. Private repositories get 2,000 free minutes per month on the free plan.

Core Concepts

Understanding these components is essential:

Workflow: - Automated process defined in YAML file - Stored in .github/workflows/ directory - Contains one or more jobs Event (Trigger): - Specific activity that starts a workflow - Examples: push, pull_request, schedule, manual Job: - Set of steps that run on the same runner - Jobs run in parallel by default - Can be configured to run sequentially Step: - Individual task within a job - Runs a command or an action - Steps run sequentially within a job Action: - Reusable unit of code - Can be from GitHub Marketplace or custom - Building blocks of steps Runner: - Server that runs your workflows - GitHub-hosted or self-hosted - Available for Linux, Windows, macOS

Your First Workflow

Let's create a simple workflow that runs on every push:

# Create workflow directory mkdir -p .github/workflows # Create workflow file cat > .github/workflows/hello-world.yml <<'EOF' name: Hello World # When to run this workflow on: push: branches: [ main ] # Jobs to run jobs: greet: runs-on: ubuntu-latest steps: - name: Print greeting run: echo "Hello, GitHub Actions!" - name: Print date run: date EOF # Commit and push git add .github/workflows/hello-world.yml git commit -m "Add Hello World workflow" git push

After pushing, check the Actions tab on GitHub to see your workflow run!

Pro Tip: Workflow files must be in the .github/workflows/ directory and have a .yml or .yaml extension.

Common Workflow Triggers

Configure when your workflows should run:

# Run on push to main branch on: push: branches: [ main ] # Run on pull request on: pull_request: branches: [ main ] # Run on multiple events on: push: branches: [ main, develop ] pull_request: branches: [ main ] # Run on schedule (cron) on: schedule: - cron: '0 0 * * *' # Daily at midnight # Run manually on: workflow_dispatch: # Run on specific paths on: push: paths: - 'src/**' - 'tests/**'

Basic CI Workflow (Testing)

A practical workflow that runs tests on every push:

name: CI - Run Tests on: push: branches: [ main, develop ] pull_request: branches: [ main ] jobs: test: runs-on: ubuntu-latest steps: # Checkout repository code - name: Checkout code uses: actions/checkout@v4 # Setup Node.js environment - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' # Install dependencies - name: Install dependencies run: npm ci # Run tests - name: Run tests run: npm test # Run linter - name: Run linter run: npm run lint
Understanding uses: The uses keyword runs an action from GitHub Marketplace or a repository. The run keyword executes shell commands.

Multiple Jobs in Parallel

Run different jobs simultaneously:

name: Build and Test on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build application run: npm run build test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run tests run: npm test lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run linter run: npm run lint

Sequential Jobs with Dependencies

Make jobs run in a specific order:

name: Build, Test, Deploy on: push: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm ci - run: npm run build test: needs: build # Wait for build to complete runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm ci - run: npm test deploy: needs: [build, test] # Wait for both runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm run deploy
Important: Jobs run in parallel by default. Use needs to create dependencies and ensure sequential execution.

Using Matrix Strategy

Test across multiple versions or platforms:

name: Test Matrix on: [push] jobs: test: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] node-version: [18, 20, 22] steps: - uses: actions/checkout@v4 - name: Setup Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm ci - run: npm test

This creates 9 jobs (3 OS × 3 Node versions) that run in parallel!

Environment Variables and Secrets

Use environment variables and secrets securely:

name: Deploy with Secrets on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest env: NODE_ENV: production API_URL: https://api.example.com steps: - uses: actions/checkout@v4 - name: Deploy to server env: DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} API_TOKEN: ${{ secrets.API_TOKEN }} run: | echo "Deploying to production..." # Use $DEPLOY_KEY and $API_TOKEN securely
Adding Secrets: Go to repository Settings → Secrets and variables → Actions → New repository secret. Secrets are encrypted and never exposed in logs.

Conditional Steps

Run steps only when conditions are met:

name: Conditional Workflow on: [push, pull_request] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run on main only if: github.ref == 'refs/heads/main' run: echo "This is the main branch" - name: Run on PR only if: github.event_name == 'pull_request' run: echo "This is a pull request" - name: Run on success if: success() run: echo "Previous steps succeeded" - name: Run on failure if: failure() run: echo "Previous steps failed"

Caching Dependencies

Speed up workflows by caching dependencies:

name: Build with Cache on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' # Cache node_modules - name: Cache dependencies uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node- - run: npm ci - run: npm run build
Cache Benefits: Caching can reduce workflow execution time by 40-60% by avoiding re-downloading dependencies on every run.

Status Badges

Add workflow status badges to your README:

# Badge URL format: https://github.com/{owner}/{repo}/actions/workflows/{workflow-file}/badge.svg # Example in README.md: ![CI](https://github.com/username/repo/actions/workflows/ci.yml/badge.svg) # With branch specification: ![CI](https://github.com/username/repo/actions/workflows/ci.yml/badge.svg?branch=main)

GitHub Marketplace Actions

Popular actions you can use in your workflows:

Essential Actions: # Checkout code - uses: actions/checkout@v4 # Setup programming languages - uses: actions/setup-node@v4 - uses: actions/setup-python@v5 - uses: actions/setup-java@v4 - uses: actions/setup-go@v5 # Upload/Download artifacts - uses: actions/upload-artifact@v4 - uses: actions/download-artifact@v4 # Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v4 # Send Slack notification - uses: slackapi/slack-github-action@v1 # Docker build and push - uses: docker/build-push-action@v5

Browse more actions at: https://github.com/marketplace?type=actions

Workflow Example: Deploy to GitHub Pages

A complete workflow for deploying a static site:

name: Deploy to GitHub Pages on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm ci - name: Build site run: npm run build - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./dist

Viewing Workflow Results

Check your workflow status on GitHub:

# On GitHub: 1. Go to your repository 2. Click "Actions" tab 3. See all workflow runs 4. Click any run to view details 5. Expand steps to see logs # Workflow statuses: ✓ Success (green check) ✗ Failure (red X) ⊙ In progress (yellow circle) ○ Cancelled (grey circle) − Skipped

Practical Exercise:

Task: Create a CI workflow for your project

  1. Create .github/workflows/ci.yml in your repository
  2. Configure it to run on push and pull_request to main
  3. Add steps to:
    • Checkout code
    • Setup your language environment (Node, Python, etc.)
    • Install dependencies
    • Run tests
    • Run linter (if available)
  4. Commit and push the workflow file
  5. View the workflow run in the Actions tab
  6. Add a status badge to your README

Expected Outcome: You'll have automated testing that runs on every push and pull request, with a visible status badge.

Best Practices

✓ Use specific action versions (@v4, not @main) ✓ Cache dependencies to speed up workflows ✓ Use secrets for sensitive data ✓ Set appropriate permissions (least privilege) ✓ Use matrix strategy for cross-platform testing ✓ Keep workflows focused and modular ✓ Add meaningful names to jobs and steps ✓ Use conditional execution to save resources ✓ Monitor workflow usage and costs ✓ Pin action versions for reproducibility

Troubleshooting Workflows

Common issues and solutions:

Problem: Workflow doesn't trigger - Check file is in .github/workflows/ - Verify YAML syntax is valid - Ensure trigger conditions are met Problem: Permission denied - Add required permissions to workflow - Check repository secrets are set - Verify token has correct scopes Problem: Slow workflow - Use caching for dependencies - Run jobs in parallel - Use matrix strategy efficiently Problem: Tests fail in CI but pass locally - Check environment differences - Verify dependencies are installed - Check environment variables - Review workflow logs carefully

Summary

In this lesson, you learned:

  • GitHub Actions automate CI/CD workflows directly in GitHub
  • Workflows are YAML files in .github/workflows/
  • Key components: events, jobs, steps, actions, runners
  • Common triggers: push, pull_request, schedule, workflow_dispatch
  • Jobs run in parallel by default; use needs for dependencies
  • Matrix strategy tests across multiple configurations
  • Secrets keep sensitive data secure
  • GitHub Marketplace provides thousands of reusable actions
  • Status badges show workflow status in your README
Next Up: In the next lesson, we'll explore Git Flow, a popular branching workflow for managing releases!