Docs
Guide

Writing GitHub Actions Workflows: A Creative Guide

GitHub Actions allows you to automate your workflows, from continuous integration to deployment. In this guide, we'll explore the basics of writing GitHub Actions workflows with creativity and examples.

Understanding Workflow Files

Workflow files are written in YAML (YAML Ain't Markup Language), a human-readable data serialization format. They define a set of steps to be executed when specific events occur in your repository.

Example: Hello World Workflow

name: Hello World
on:
  push:
    branches:
      - main
 
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Greet the World
        run: echo "Hello, World!"

In this example, we've created a workflow named "Hello World" that triggers on any push to the main branch. It runs on an Ubuntu environment and executes a single step to echo "Hello, World!"

Events and Triggers

Events trigger workflows. They can be events like pushes, pull requests, issues, and more. You can customize when your workflow runs based on these events.

Example: Trigger on Pull Request

name: PR Checks
on:
  pull_request:
    types:
      - opened
      - synchronize
 
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - name: Check PR
        run: echo "Checking Pull Request..."

This workflow triggers when a pull request is opened or synchronized. It then runs a validation step.

Jobs and Steps

A workflow can contain one or more jobs. Each job runs in parallel and contains a series of steps.

Example: Parallel Jobs

name: Parallel Jobs
on:
  push:
    branches:
      - main
 
jobs:
  job1:
    runs-on: ubuntu-latest
    steps:
      - name: Step 1
        run: echo "Step 1"
 
  job2:
    runs-on: ubuntu-latest
    steps:
      - name: Step 2
        run: echo "Step 2"

In this example, we have two jobs (job1 and job2) that run in parallel when a push occurs. Each job has a single step.

Actions and Environments

Actions are reusable units of code. They can be from the GitHub Marketplace or custom actions defined in your repository. Environments define where jobs run.

Example: Deploy to Production

name: Deploy to Production
on:
  push:
    branches:
      - main
 
jobs:
  deploy:
    runs-on: production-environment
    steps:
      - name: Deploy
        uses: actions/checkout@v2
      - name: Deploy to Production
        run: ./deploy.sh

Here, the deploy job runs on a custom production-environment. It checks out the code and then deploys using a custom script.

Matrix Builds and Strategy

Matrix builds allow you to run a job with different configurations. You can define a strategy for matrix builds.

Example: Matrix Build

name: Matrix Build
on:
  push:
    branches:
      - main
 
jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [10, 12, 14]
    steps:
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v2
        with:
          node-version: ${{ matrix.node-version }}
      - name: Install Dependencies
        run: npm install
      - name: Build
        run: npm run build

In this example, the build job is defined with a matrix strategy for different Node.js versions. It installs dependencies and builds the project for each version.

Secrets and Environment Variables

You can store sensitive information as secrets and use them in your workflows. Environment variables provide a way to pass data between steps.

Example: Using Secrets

name: Use Secrets
on:
  push:
    branches:
      - main
 
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Use Secret
        run: echo ${{ secrets.MY_SECRET }}
        env:
          MY_SECRET: ${{ secrets.MY_SECRET }}

Here, the deploy job uses a secret named MY_SECRET and prints its value.

Customizing Outputs and Artifacts

You can customize the outputs of steps and create artifacts to store files. These can be used in subsequent jobs.

Example: Create Artifact

name: Create Artifact
on:
  push:
    branches:
      - main
 
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Build
        run: ./build.sh
      - name: Archive Build
        uses: actions/upload-artifact@v2
        with:
          name: my-artifact
          path: build/

In this example, the build job creates an artifact named my-artifact from the build/ directory.

Conditional Execution and Timeouts

You can conditionally execute steps and set timeouts for jobs.

Example: Conditional Step

name: Conditional Step
on:
  push:
    branches:
      - main
 
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Test
        run: echo "Running tests..."
      - name: Notify on Failure
        if: failure()
        run: echo "Tests failed!"

Here, the Notify on Failure step only runs if the previous step fails.

Conclusion

This creative guide has covered the basics of writing GitHub Actions workflows. Combine these elements to create powerful automation for your repositories. Experiment, iterate, and automate with flair! Happy coding! 🚀