Skip to content

Advanced GitHub Actions Workflows, Service Containers, Scheduling, Composite Actions, and Caching

Updated: at 11:12 AM (6 min read)

Table of contents

Open Table of contents

Introduction

GitHub Actions has revolutionized how we automate, build, and deploy our projects directly from GitHub. While many are familiar with the basics of setting up workflows, there are advanced features that can significantly enhance your CI/CD pipelines. In this article, we’ll delve into:

Let’s explore each of these features with practical examples and code snippets.

1. Using Service Containers in GitHub Actions

What Are Service Containers?

Service containers are Docker containers that run alongside your job in a GitHub Actions workflow. They allow you to create test environments that mimic your application’s production environment, including databases, APIs, and other services your application interacts with.

Why Use Service Containers?

Configuring a Service Container

Let’s walk through setting up a PostgreSQL database as a service container in a workflow.

Workflow File: .github/workflows/ci.yml

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest # Must be a Linux runner

    services:
      postgres:
        image: postgres:13
        env:
          POSTGRES_USER: myuser
          POSTGRES_PASSWORD: mypassword
          POSTGRES_DB: mydatabase
        ports:
          - 5432:5432 # Maps container port 5432 to runner port 5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    env:
      DATABASE_HOST: localhost
      DATABASE_PORT: 5432
      DATABASE_USER: myuser
      DATABASE_PASSWORD: mypassword
      DATABASE_NAME: mydatabase

    steps:
      - uses: actions/checkout@v3

      - name: Install Dependencies
        run: |
          pip install -r requirements.txt

      - name: Run Database Migration
        run: |
          python manage.py migrate

      - name: Run Tests
        run: |
          python manage.py test

Key Points

2. Scheduling Workflows with Cron Syntax

Why Schedule Workflows?

Scheduled workflows allow you to run tasks at specific intervals, such as nightly builds, weekly reports, or periodic maintenance tasks.

Configuring a Scheduled Workflow

Workflow File: .github/workflows/schedule.yml

# Run at minute 0 past every 6th hour (UTC)

on:
  schedule:
    - cron: "0 */6 * * *"

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Run Build Script
        run: |
          ./build.sh

Understanding Cron Syntax

The cron expression 0 */6 * * * breaks down as:

Important Notes

3. Creating Composite Actions

What Are Composite Actions?

Composite actions allow you to bundle multiple steps into a single action. This promotes reusability and simplifies your workflows by avoiding code duplication.

Creating a Composite Action

Directory Structure

my-action/
├── action.yml
└── scripts/
    └── my_script.sh

Action Definition: my-action/action.yml

name: My Composite Action
description: Runs multiple steps as a single action
inputs:
  greet:
    description: "Who to greet"
    default: "World"
runs:
  using: "composite"
  steps:
    - name: Checkout Code
      uses: actions/checkout@v3

    - name: Run a Script
      run: |
        echo "Hello, ${{ inputs.greet }}!"

Using the Composite Action in a Workflow

Workflow File: .github/workflows/use-composite.yml

name: Use Composite Action

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Use My Composite Action
        uses: ./my-action
        with:
          greet: "GitHub Actions"

Benefits

4. Environment Protection Rules and Manual Approvals

Why Use Environment Protection?

In multi-environment deployments (e.g., development, staging, production), you might want manual approvals before deploying to sensitive environments like production.

Setting Up Environments in GitHub

  1. Navigate to Settings: Go to your repository’s settings.
  2. Select Environments: Click on Environments.
  3. Create Environment: Add environments like development and production.

Configuring Protection Rules

  1. Select Environment: Click on your environment (e.g., production).
  2. Configure Protection Rules:
    • Required Reviewers: Add users or teams who can approve deployments.
    • Wait Timer: (Optional) Add a delay before deployment proceeds.
    • Environment Secrets: Add secrets specific to the environment.

Modifying Your Workflow

Workflow File: .github/workflows/deploy.yml

name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://your-production-url.com
    steps:
      - uses: actions/checkout@v3

      - name: Deploy to Production
        run: |
          echo "Deploying to production..."

Manual Approval Process

When the workflow reaches the deployment job:

  1. Pending Approval: The job pauses and waits for approval.
  2. Notification: Approvers receive an email and a GitHub notification.
  3. Approval: An approver can approve or reject the deployment.
  4. Deployment Proceeds: Upon approval, the job continues.

Notes

5. Caching Dependencies to Speed Up Workflows

The Need for Caching

Dependencies often take time to download and install. Caching these can significantly speed up your workflows, saving time and resources.

Built-in Caching with Setup Actions

For certain languages, the setup actions support caching out of the box.

Node.js: actions/setup-node@v3

- uses: actions/setup-node@v3
  with:
    node-version: "16"
    cache: "npm"

Python: actions/setup-python@v4

- uses: actions/setup-python@v4
  with:
    python-version: "3.9"
    cache: "pip"

Java: actions/setup-java@v3

- uses: actions/setup-java@v3
  with:
    java-version: "17"
    distribution: "adopt"
    cache: "maven"

Ruby: actions/setup-ruby@v1

- uses: actions/setup-ruby@v1
  with:
    ruby-version: "3.0"
    bundler-cache: true

Using the Cache Action Directly

For custom caching needs, use actions/cache@v3.

Workflow File: .github/workflows/cache.yml

name: Cache Example

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Cache Dependencies
        id: cache-deps
        uses: actions/cache@v3
        with:
          path: |
            ~/.cache/pip
          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
          restore-keys: |
            ${{ runner.os }}-pip-

      - name: Install Dependencies
        if: steps.cache-deps.outputs.cache-hit != 'true'
        run: |
          pip install -r requirements.txt --cache-dir ~/.cache/pip

      - name: Run Build
        run: |
          python setup.py build

Explanation

Cache Limitations

Conclusion

Mastering these advanced features of GitHub Actions can greatly enhance your CI/CD workflows:

By integrating these features, you can create more efficient, maintainable, and secure pipelines that save time and reduce complexity.