Skip to content

Lowkh/Practice_github_actions_GenAI

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

GitHub Actions Full Suite: Comprehensive Practical Curriculum

Overview

This comprehensive suite contains six progressive practicals that build from fundamental concepts to production-grade CI/CD pipelines. The suite is designed for polytechnic students progressing from beginner to intermediate/advanced levels over a 6-12 week period.


Practical 1: Foundations of GitHub Actions

Duration: 2 hours | Level: Beginner

Learning Objectives

  • Understand core GitHub Actions concepts
  • Create and execute a simple workflow
  • Interpret workflow logs
  • Understand YAML syntax fundamentals

Prerequisites

  • GitHub account (free tier)
  • A repository (or ability to create one)
  • Basic Git knowledge

Part A: Core Concepts (20 minutes)

What is GitHub Actions?

GitHub Actions is a CI/CD platform that allows you to automate your workflow directly in your GitHub repository. Automation happens through events—when something happens in your repository (push, pull request, etc.), a workflow automatically triggers.

Key Terminology

Term Definition Example
Workflow An automated process defined in YAML File: .github/workflows/build.yml
Event Activity that triggers a workflow push, pull_request, schedule
Job A set of steps running on same runner Build job, Test job
Step Individual task within a job Run test, Deploy application
Action Reusable code unit performing a task actions/checkout@v4
Runner Virtual machine executing the workflow Ubuntu, Windows, macOS
Artifact Files generated during workflow Build output, test reports

Part B: Your First Workflow (40 minutes)

Exercise 1: Create a Hello World Workflow

Steps:

  1. Create a new repository called github-actions-learning
  2. Navigate to the Actions tab
  3. Click set up a workflow yourself
  4. Create a file named hello-world.yml with the following content:
name: Hello World Workflow

on: push

jobs:
  hello-job:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Print greeting
        run: echo "Hello from GitHub Actions!"
      
      - name: Print system info
        run: |
          echo "Operating System: $(uname -s)"
          echo "Architecture: $(uname -m)"
          echo "Current time: $(date)"
  1. Commit the file
  2. Go to Actions tab and observe the workflow execution
  3. Click on the completed workflow to view logs

Exercise 2: Understanding YAML Syntax

Key concepts:

  • Indentation matters: Use 2 spaces (never tabs)
  • Colons (:): Separate keys from values
  • Hyphens (-): Indicate list items
  • Pipes (|): Multi-line string values
  • Comments: Lines starting with #

Example with syntax annotations:

name: Syntax Example  # String value after colon

on: push  # Event trigger

jobs:  # Start of jobs section (key with no value)
  demo-job:  # Job name
    runs-on: ubuntu-latest  # Configuration key-value
    
    steps:  # List of steps
      - name: First step  # List item with name key
        run: echo "Step 1"
      
      - name: Multi-line step
        run: |  # Pipe for multi-line
          echo "Line 1"
          echo "Line 2"
          echo "Line 3"

Part C: Understanding Logs (20 minutes)

Interpreting Workflow Output

When you click a completed workflow, you see:

  1. Workflow Summary - Overall status, duration, and trigger info
  2. Jobs Section - List of all jobs with individual statuses
  3. Step Details - Expandable sections showing each step's output

Log Indicators

Symbol Meaning Color
Step succeeded Green
Step failed Red
Step skipped Gray
Warning/notice Yellow

Exercise 3: Debug with Logs

  1. Create a workflow with intentional errors:
name: Debug Practice

on: push

jobs:
  debug-job:
    runs-on: ubuntu-latest
    
    steps:
      - name: Success step
        run: echo "This will succeed"
      
      - name: List directory
        run: ls -la
      
      - name: Show environment
        run: |
          echo "User: $(whoami)"
          echo "Home: $HOME"
          echo "Path: $PATH"
  1. Commit and push
  2. View the logs and identify what information each step provides

Part D: Review Questions (10 minutes)

  1. What triggers the workflow in your hello-world example?
  2. Name the three jobs components in GitHub Actions
  3. What does uses: actions/checkout@v4 do?
  4. Why is YAML indentation important?
  5. How would you run multiple commands in a single step?

Practical 2: Workflows and Events

Duration: 2.5 hours | Level: Beginner

Learning Objectives

  • Understand different event triggers
  • Create workflows responding to specific events
  • Use event contexts and payloads
  • Filter workflows based on conditions

Prerequisites

  • Completion of Practical 1

Part A: Understanding Events (30 minutes)

Common Events

Push Events Triggered when code is pushed to a branch. Perfect for CI tasks.

on: push

Pull Request Events Triggered when a pull request is opened, edited, or synchronized.

on: pull_request

Scheduled Events Triggered at specific times using cron syntax.

on:
  schedule:
    - cron: '0 9 * * 1'  # 9 AM every Monday UTC

Manual Trigger Events Triggered manually from GitHub UI using workflow_dispatch.

on: workflow_dispatch

Part B: Event Filtering (40 minutes)

Exercise 1: Push Event Filtering

Create workflows that trigger only on specific conditions:

name: Filtered Push Events

on:
  push:
    branches:
      - main
      - develop
    paths:
      - 'src/**'
      - '.github/workflows/**'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "Changes detected in src or workflows"

This workflow runs only when:

  • Push happens to main or develop branch
  • AND changes are in src/ or .github/workflows/ directories

Exercise 2: Pull Request Events

name: PR Quality Checks

on:
  pull_request:
    types: [opened, synchronize, reopened]
    branches:
      - main

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: PR Info
        run: |
          echo "PR Title: ${{ github.event.pull_request.title }}"
          echo "PR Author: ${{ github.event.pull_request.user.login }}"
          echo "PR Number: ${{ github.event.pull_request.number }}"

Key concepts:

  • types: specifies which PR actions trigger the workflow
  • Context variables like github.event.pull_request contain PR data

Exercise 3: Scheduled Workflows

name: Daily Health Check

on:
  schedule:
    - cron: '0 2 * * *'  # 2 AM UTC every day
  workflow_dispatch:  # Also allow manual trigger

jobs:
  health-check:
    runs-on: ubuntu-latest
    steps:
      - name: Check system
        run: echo "Running daily health check"
      
      - name: Current date
        run: date

Cron format: minute hour day-of-month month day-of-week

Common patterns:

  • 0 9 * * 1 - 9 AM every Monday
  • 0 */6 * * * - Every 6 hours
  • 0 0 * * 0 - Midnight every Sunday
  • */15 * * * * - Every 15 minutes

Part C: Event Context and Variables (35 minutes)

Available Context Variables

All workflows have access to the github context containing information about the triggering event:

name: Context Variables Demo

on: push

jobs:
  demo:
    runs-on: ubuntu-latest
    steps:
      - run: |
          echo "Repository: ${{ github.repository }}"
          echo "Event: ${{ github.event_name }}"
          echo "Actor: ${{ github.actor }}"
          echo "Ref: ${{ github.ref }}"
          echo "Commit SHA: ${{ github.sha }}"
          echo "Workspace: ${{ github.workspace }}"

Exercise: Conditional Execution

name: Conditional Workflows

on: push

jobs:
  conditional-job:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Run only on main
        if: github.ref == 'refs/heads/main'
        run: echo "This runs only on main branch"
      
      - name: Run on all branches
        run: echo "This always runs"
      
      - name: Run if push (not pull request)
        if: github.event_name == 'push'
        run: echo "This is a push event"

Part D: Activities (30 minutes)

Activity 1: Multi-Event Workflow

Create a workflow that:

  1. Triggers on push to main and develop branches
  2. Triggers on pull requests to main
  3. Triggers manually via workflow_dispatch
  4. Prints different messages based on the event type

Solution structure:

name: Multi-Event Workflow

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
  workflow_dispatch:

jobs:
  respond:
    runs-on: ubuntu-latest
    steps:
      - run: |
          if [ "${{ github.event_name }}" = "push" ]; then
            echo "Code was pushed"
          elif [ "${{ github.event_name }}" = "pull_request" ]; then
            echo "Pull request detected"
          elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
            echo "Manual trigger"
          fi

Activity 2: Scheduled Report

Create a workflow that:

  1. Runs every day at 8 AM UTC
  2. Allows manual trigger
  3. Generates a simple timestamp report

Practical 3: Jobs, Steps, and Actions

Duration: 3 hours | Level: Beginner to Intermediate

Learning Objectives

  • Structure complex workflows with multiple jobs
  • Understand job dependencies
  • Use actions from GitHub Marketplace
  • Create reusable step patterns

Prerequisites

  • Completion of Practicals 1 and 2

Part A: Job Architecture (30 minutes)

Sequential vs Parallel Jobs

Parallel Jobs (Default) Jobs run simultaneously:

name: Parallel Jobs

on: push

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Testing"
  
  lint:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Linting"
  
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building"

All three jobs start at roughly the same time.

Sequential Jobs with Dependencies Control job execution order:

name: Sequential Jobs

on: push

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building"
  
  test:
    needs: build  # This job waits for 'build'
    runs-on: ubuntu-latest
    steps:
      - run: echo "Testing"
  
  deploy:
    needs: test  # This job waits for 'test'
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying"

Execution order: build → test → deploy

Part B: Using Actions (45 minutes)

What are Actions?

Actions are reusable blocks of code. They can be:

  • Built by GitHub (official actions)
  • Built by the community (GitHub Marketplace)
  • Custom (created by you)

Exercise 1: Official GitHub Actions

name: Using Official Actions

on: push

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      # Checkout action
      - uses: actions/checkout@v4
      
      # Setup Node.js
      - uses: actions/setup-node@v4
        with:
          node-version: '18'
      
      # Upload artifacts
      - name: Create artifact
        run: mkdir -p dist && echo "Build output" > dist/index.html
      
      - uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: dist/

Common Actions

Action Purpose Example
actions/checkout@v4 Clone repository Get your code
actions/setup-node@v4 Setup Node.js Install Node.js
actions/setup-python@v4 Setup Python Install Python
actions/upload-artifact@v4 Upload files Save build artifacts
actions/download-artifact@v4 Download files Retrieve artifacts
actions/cache@v4 Cache dependencies Speed up builds

Exercise 2: Node.js Workflow

Create a complete Node.js build workflow:

name: Node.js CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        node-version: [16, 18, 20]
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run tests
        run: npm test
      
      - name: Build application
        run: npm run build
      
      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build-node-${{ matrix.node-version }}
          path: dist/

Key features:

  • Matrix strategy tests multiple Node versions
  • Caching speeds up npm install
  • Artifacts saved for each version

Part C: Job Outputs and Data Passing (35 minutes)

Passing Data Between Jobs

name: Job Data Flow

on: push

jobs:
  setup:
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.extract.outputs.version }}
      timestamp: ${{ steps.time.outputs.time }}
    
    steps:
      - uses: actions/checkout@v4
      
      - id: extract
        run: echo "version=1.2.3" >> $GITHUB_OUTPUT
      
      - id: time
        run: echo "time=$(date)" >> $GITHUB_OUTPUT
  
  deploy:
    needs: setup
    runs-on: ubuntu-latest
    steps:
      - run: |
          echo "Deploying version: ${{ needs.setup.outputs.version }}"
          echo "Time: ${{ needs.setup.outputs.timestamp }}"

Key points:

  • outputs: declares available outputs from a job
  • $GITHUB_OUTPUT sets output values
  • Dependent jobs access outputs via needs.jobname.outputs.variable

Part D: Matrix Builds (35 minutes)

Why Matrix?

Test your code across multiple configurations simultaneously:

name: Matrix Testing

on: push

jobs:
  test:
    runs-on: ${{ matrix.os }}
    
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        python-version: ['3.8', '3.9', '3.10', '3.11']
    
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
      
      - run: |
          python -m pip install pytest
          pytest tests/

This creates 12 job combinations:

  • 3 operating systems × 4 Python versions
  • All run in parallel
  • Faster feedback on compatibility issues

Matrix Include/Exclude

strategy:
  matrix:
    include:
      - os: ubuntu-latest
        python-version: '3.8'
        experimental: false
      - os: ubuntu-latest
        python-version: '3.11'
        experimental: true
  exclude:
    - os: windows-latest
      python-version: '3.8'

Part E: Practical Activities (35 minutes)

Activity 1: Build and Test Pipeline

Create a workflow that:

  1. Checks out code
  2. Builds in parallel across 3 Node versions
  3. Runs tests after builds complete
  4. Uploads artifacts

Activity 2: Multi-Platform Deployment

Create a workflow that:

  1. Builds on Ubuntu, Windows, and macOS
  2. Runs tests on each platform
  3. Reports success/failure for each platform
  4. Creates artifacts for successful builds

Practical 4: Testing and CI Workflows

Duration: 3 hours | Level: Intermediate

Learning Objectives

  • Implement automated testing in workflows
  • Use testing frameworks with GitHub Actions
  • Create comprehensive CI pipelines
  • Report test results

Prerequisites

  • Completion of Practicals 1-3

Part A: Testing Frameworks Setup (40 minutes)

Node.js with Jest

name: Node.js Testing

on: push

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: '18'
          cache: 'npm'
      
      - run: npm ci
      
      - name: Run unit tests
        run: npm test -- --coverage
      
      - name: Upload coverage
        uses: actions/upload-artifact@v4
        with:
          name: coverage-report
          path: coverage/

Python with pytest

name: Python Testing

on: push

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.8', '3.9', '3.10', '3.11']
    
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
      
      - run: |
          python -m pip install --upgrade pip
          pip install pytest pytest-cov
          pip install -r requirements.txt
      
      - name: Run tests
        run: pytest --cov=src tests/

Java with Maven

name: Java Testing

on: push

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-java@v3
        with:
          java-version: '11'
          distribution: 'temurin'
          cache: maven
      
      - run: mvn clean test

Part B: Code Quality and Linting (40 minutes)

Linting for Multiple Languages

name: Code Quality

on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      # JavaScript/TypeScript linting
      - uses: actions/setup-node@v4
        with:
          node-version: '18'
      
      - run: npm install -g eslint
      - run: eslint src/ --max-warnings 0
      
      # Python linting
      - uses: actions/setup-python@v4
      
      - run: pip install pylint
      - run: pylint src/*.py

Using Super Linter

name: Super Linter

on: push

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      
      - uses: github/super-linter@v4
        env:
          DEFAULT_BRANCH: main
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Part C: Comprehensive CI Pipeline (40 minutes)

Full Pipeline Example

name: Complete CI Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  lint:
    name: Code Quality
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: '18'
          cache: 'npm'
      
      - run: npm ci
      - run: npm run lint
      - run: npm run format:check
  
  test:
    name: Unit Tests
    runs-on: ubuntu-latest
    needs: lint
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: '18'
          cache: 'npm'
      
      - run: npm ci
      
      - name: Run tests
        run: npm test -- --coverage
      
      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          files: ./coverage/lcov.info
  
  build:
    name: Build Artifacts
    runs-on: ubuntu-latest
    needs: test
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: '18'
          cache: 'npm'
      
      - run: npm ci
      
      - run: npm run build
      
      - uses: actions/upload-artifact@v4
        with:
          name: build
          path: dist/
  
  security:
    name: Security Scan
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - uses: github/super-linter@v4
        env:
          DEFAULT_BRANCH: main
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Pipeline flow:

  1. Lint runs first
  2. Tests run after lint passes
  3. Build runs after tests pass
  4. Security scan runs in parallel

Part D: Test Reporting (40 minutes)

Publishing Test Results

name: Test Reporting

on: push

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: '18'
      
      - run: npm ci
      
      - name: Run tests with reports
        run: npm test -- --reporters=json --reporters=junit
        continue-on-error: true
      
      - name: Publish test results
        uses: EnricoMi/publish-unit-test-result-action@v2
        if: always()
        with:
          files: test-results.xml

Coverage Reports

- name: Generate coverage
  run: npm test -- --coverage --coverageReporters=json

- name: Comment coverage
  uses: romeovs/lcov-reporter-action@v0.3.1
  with:
    lcov-file: ./coverage/lcov.info

Practical 5: Deployment and CD Workflows

Duration: 3.5 hours | Level: Intermediate to Advanced

Learning Objectives

  • Create deployment workflows
  • Implement environment-specific deployments
  • Handle deployment secrets securely
  • Create rollback strategies

Prerequisites

  • Completion of Practicals 1-4

Part A: Secrets and Environment Variables (35 minutes)

Using Secrets

name: Deployment with Secrets

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy with credentials
        env:
          API_KEY: ${{ secrets.PRODUCTION_API_KEY }}
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
        run: |
          echo "Deploying to production"
          # Your deployment script here

How to add secrets:

  1. Repository → Settings → Secrets and variables → Actions
  2. Click "New repository secret"
  3. Add name (e.g., PRODUCTION_API_KEY) and value
  4. Reference in workflow: ${{ secrets.SECRET_NAME }}

Environment-Specific Configuration

name: Multi-Environment Deployment

on:
  push:
    branches:
      - main
      - develop

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy
        env:
          ENV_VAR: ${{ secrets.ENV_SPECIFIC_VAR }}
          DEPLOY_URL: ${{ vars.DEPLOY_URL }}
        run: echo "Deploying to ${{ github.ref }}"

Part B: Deployment Strategies (50 minutes)

Staging then Production

name: Staged Deployment

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      build-number: ${{ steps.build.outputs.number }}
    steps:
      - uses: actions/checkout@v4
      - id: build
        run: echo "number=${{ github.run_number }}" >> $GITHUB_OUTPUT
      - run: echo "Building application"
  
  deploy-staging:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: staging
      url: https://staging.example.com
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to staging
        run: |
          echo "Deploying build ${{ needs.build.outputs.build-number }} to staging"
  
  test-staging:
    needs: deploy-staging
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run integration tests
        run: npm run test:integration -- --url https://staging.example.com
  
  deploy-production:
    needs: [build, test-staging]
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://example.com
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to production
        run: |
          echo "Deploying build ${{ needs.build.outputs.build-number }} to production"

Blue-Green Deployment

name: Blue-Green Deployment

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy to green environment
        run: |
          echo "Deploying new version to green"
          # Deploy new version
      
      - name: Run smoke tests
        run: |
          echo "Testing green environment"
          # Run tests against new deployment
      
      - name: Switch traffic to green
        run: |
          echo "Switching traffic from blue to green"
          # Switch load balancer
      
      - name: Keep blue as rollback
        if: always()
        run: echo "Blue environment ready for rollback"

Part C: Docker and Container Deployment (45 minutes)

Build and Push Docker Image

name: Build and Deploy Docker

on:
  push:
    branches: [main]
    tags: ['v*']

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
      
      - name: Log in to Container Registry
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      
      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v4
        with:
          images: ghcr.io/${{ github.repository }}
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
      
      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
  
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Deploy to Kubernetes
        run: |
          echo "Deploying container to Kubernetes cluster"
          # kubectl deployment commands here

Part D: Monitoring and Notifications (35 minutes)

Slack Notifications

name: Deployment with Notifications

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy
        id: deploy
        run: |
          echo "Deploying..."
          # Deployment commands
          echo "status=success" >> $GITHUB_OUTPUT
      
      - name: Notify Slack - Success
        if: steps.deploy.outputs.status == 'success'
        uses: slackapi/slack-github-action@v1.24.0
        with:
          webhook-url: ${{ secrets.SLACK_WEBHOOK }}
          payload: |
            {
              "text": "✅ Deployment Successful",
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "*Deployment Successful*\nRepository: ${{ github.repository }}\nBranch: ${{ github.ref }}\nCommit: ${{ github.sha }}"
                  }
                }
              ]
            }
      
      - name: Notify Slack - Failure
        if: failure()
        uses: slackapi/slack-github-action@v1.24.0
        with:
          webhook-url: ${{ secrets.SLACK_WEBHOOK }}
          payload: |
            {
              "text": "❌ Deployment Failed",
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "*Deployment Failed*\nRepository: ${{ github.repository }}\nError: Check logs"
                  }
                }
              ]
            }

Practical 6: Advanced Workflows and Optimization

Duration: 3.5 hours | Level: Advanced

Learning Objectives

  • Create reusable workflows
  • Optimize workflow performance
  • Implement advanced caching strategies
  • Handle complex workflow scenarios

Prerequisites

  • Completion of Practicals 1-5

Part A: Reusable Workflows (50 minutes)

Creating a Reusable Workflow

File: .github/workflows/reusable-test.yml

name: Reusable Test Workflow

on:
  workflow_call:
    inputs:
      node-version:
        required: false
        type: string
        default: '18'
      test-command:
        required: false
        type: string
        default: 'npm test'

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
          cache: 'npm'
      
      - run: npm ci
      
      - run: ${{ inputs.test-command }}

Using a Reusable Workflow

File: .github/workflows/ci.yml

name: CI Pipeline

on: [push, pull_request]

jobs:
  test-node-16:
    uses: ./.github/workflows/reusable-test.yml
    with:
      node-version: '16'
      test-command: 'npm test -- --coverage'
  
  test-node-18:
    uses: ./.github/workflows/reusable-test.yml
    with:
      node-version: '18'
  
  test-node-20:
    uses: ./.github/workflows/reusable-test.yml
    with:
      node-version: '20'

Part B: Performance Optimization (50 minutes)

Caching Dependencies

name: Optimized Build

on: push

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      # Cache Node modules
      - uses: actions/cache@v3
        with:
          path: ~/.npm
          key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-npm-
      
      # Cache pip packages for Python
      - uses: actions/cache@v3
        with:
          path: ~/.cache/pip
          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
      
      - run: npm ci
      - run: npm run build

Parallel Matrix with Caching

name: Optimized Matrix Build

on: push

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [16, 18, 20]
        include:
          - node-version: 18
            cache-key-prefix: primary
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/cache@v3
        with:
          path: ~/.npm
          key: ${{ runner.os }}-npm-${{ matrix.cache-key-prefix }}-${{ hashFiles('**/package-lock.json') }}
      
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      
      - run: npm ci
      - run: npm test

Part C: Complex Workflow Scenarios (50 minutes)

Conditional Deployments

name: Smart Deployment

on:
  push:
    branches: [main, develop, hotfix/*]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm test
  
  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.event_name == 'push'
    steps:
      - uses: actions/checkout@v4
      
      - name: Determine environment
        id: env
        run: |
          if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
            echo "environment=production" >> $GITHUB_OUTPUT
          elif [[ "${{ github.ref }}" == "refs/heads/develop" ]]; then
            echo "environment=staging" >> $GITHUB_OUTPUT
          elif [[ "${{ github.ref }}" == refs/heads/hotfix/* ]]; then
            echo "environment=hotfix" >> $GITHUB_OUTPUT
          fi
      
      - name: Deploy to ${{ steps.env.outputs.environment }}
        run: echo "Deploying to ${{ steps.env.outputs.environment }}"

Approval Workflows

name: Approval-Based Deployment

on: workflow_dispatch

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm run build
  
  request-approval:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Trigger approval
        run: echo "Build ready for approval"
  
  deploy-production:
    needs: request-approval
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://example.com
    steps:
      - uses: actions/checkout@v4
      - run: echo "Deploying to production"

Part D: Troubleshooting and Best Practices (30 minutes)

Common Issues and Solutions

Issue Cause Solution
Workflow not triggering Wrong branch/event Check on: configuration
Job timeout Long-running tasks Use longer timeout or parallelize
Cache not working Key mismatch Use hashFiles() for consistent keys
Permission denied Missing permissions Check permissions: in workflow
Out of memory Large dependencies Use smaller runners or parallelize

Debugging Techniques

name: Debug Workflow

on: push

jobs:
  debug:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      # Enable debug logging
      - name: Enable debug logging
        run: |
          echo "RUNNER_DEBUG=1" >> $GITHUB_ENV
      
      # Print environment
      - name: Print environment
        run: |
          echo "OS: $(uname -s)"
          echo "Working directory: $(pwd)"
          echo "Disk space: $(df -h)"
          echo "Memory: $(free -h)"
      
      # List secrets (sanitized)
      - name: Check secrets available
        run: |
          if [ -n "${{ secrets.SOME_SECRET }}" ]; then
            echo "Secret is set (value redacted)"
          fi

Performance Best Practices

  1. Cache aggressively - Use caching for dependencies
  2. Use matrix efficiently - Run tests in parallel across versions
  3. Fail fast - Run quick checks before slow ones
  4. Artifact management - Remove old artifacts to save space
  5. Workflow optimization - Use conditional steps with if:

Integration Activities (Full Suite)

Activity 1: Complete Real-World Project

Create a full CI/CD pipeline for a Node.js application that:

  1. Triggers on push to main/develop and all pull requests
  2. Lints code across JavaScript standards
  3. Tests with coverage reporting
  4. Builds for multiple Node versions
  5. Deploys to staging from develop branch
  6. Deploys to production from main branch with approval
  7. Notifies team via Slack on success/failure

Activity 2: Multi-Language Project

Set up GitHub Actions for a project with:

  • Frontend (Node.js + React)
  • Backend (Python + Flask)
  • Database migrations
  • Docker containerization
  • Separate deployment for each service

Activity 3: Monitoring and Compliance

Create workflows that:

  • Run security scans (SAST/DAST)
  • Generate and publish test reports
  • Monitor deployment health
  • Create automated rollback on failure
  • Generate compliance reports

Assessment Rubric

Beginner Level (Practicals 1-2)

  • Successfully create workflows with push events
  • Understand and use YAML syntax correctly
  • Interpret workflow logs and identify issues
  • Create multiple event triggers (push, PR, schedule)

Intermediate Level (Practicals 3-4)

  • Structure complex workflows with multiple jobs
  • Implement matrix builds
  • Set up testing frameworks
  • Create comprehensive CI pipelines

Advanced Level (Practicals 5-6)

  • Implement secure deployments with secrets
  • Create reusable workflow components
  • Optimize performance with caching
  • Handle complex deployment scenarios

Resources and References

Official Documentation

Learning Resources

Tools and Utilities


Conclusion

This comprehensive suite takes students from fundamental GitHub Actions concepts through production-grade CI/CD implementation. Each practical builds on previous knowledge while introducing new capabilities, ensuring mastery at each level.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors