DEV Community

Željko Šević
Željko Šević

Posted on • Edited on • Originally published at sevic.dev

GitHub actions 101

GitHub action is a CI/CD tool integrated within GitHub repositories that can run different kinds of jobs (building, testing, deployment). Store workflow files in .github/workflows inside the repository, which will be triggered based on specified conditions.

This post covers GitHub actions basics, from specifying the workflow name to configuring different jobs.

Name

Specify the name of the workflow with the name field.

# .github/workflows/config.yml
name: CI/CD pipeline
Enter fullscreen mode Exit fullscreen mode

Running

on field specifies when the workflow should be running.

Automatically

The following configuration runs on every push to a specific branch.

# .github/workflows/config.yml
on:
  push:
    branches:
      - main
Enter fullscreen mode Exit fullscreen mode

The following configuration runs on every push to every branch.

# .github/workflows/config.yml
on:
  push:
    branches:
      - '*'
Enter fullscreen mode Exit fullscreen mode

Cron jobs

The following configuration runs at a specified interval (e.g., every hour).

# .github/workflows/config.yml
on:
  schedule:
    - cron: '0 * * * *'
Enter fullscreen mode Exit fullscreen mode

Manual triggers

The following configuration enables manual triggering. Trigger it on the Actions tab by selecting the workflow and clicking the Run workflow button.

Use a manual trigger to upload apps to the Google Play console or update the GitHub profile Readme.

# .github/workflows/config.yml
on:
  workflow_dispatch:
Enter fullscreen mode Exit fullscreen mode

Environment variables

Specify with the env field. Set repository secrets in Settings → Secrets and variables → Actions page.

# .github/workflows/config.yml
env:
  API_KEY: ${{ secrets.API_KEY }}
Enter fullscreen mode Exit fullscreen mode

Jobs

Specify the job name with the name field. Otherwise, the workflow will use the jobs item as the job name.

Every job can have a separate working directory in case you have multiple subdirectories, and you want to run a different job in a different subdirectory so you can specify it within the defaults field

jobs:
  job-name:
    defaults:
      run:
        working-directory: directory-name
Enter fullscreen mode Exit fullscreen mode

Every job should have a runs-on field specified for the machine, which will be running on (e.g., ubuntu-latest) or container field with set Docker image (e.g., node:20.9.0-alpine3.17)

You can specify multiple tasks inside one job. Every task can have the following fields

  • name - task name
  • uses - GitHub action path from GitHub Marketplace
  • with - parameters for the specified GitHub action
  • run - bash commands
  • env - environment variables
# .github/workflows/config.yml
jobs:
  build:
    name: Custom build job

    runs-on: ubuntu-latest
    # container: node:20.9.0-alpine3.17

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Configure Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install and build
        run: |
          npm ci
          npm run build
Enter fullscreen mode Exit fullscreen mode

Use the needs field for running jobs sequentially. It specifies a job that has to be finished before starting the next one. Otherwise, jobs will run in parallel.

# .github/workflows/config.yml
jobs:
  build:
  # ...
  deploy:
    name: Custom deploy job
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy
        run: |
          npm run deploy
Enter fullscreen mode Exit fullscreen mode

Every job can run multiple times with different versions using a matrix strategy (e.g., Node versions 18 and 20 or multiple OS versions inside an array of objects).

# .github/workflows/config.yml
jobs:
  build:
    name: Custom build job
    strategy:
      matrix:
        node-version: [18, 20]
        os:
          [
            { name: 'linux', image: 'ubuntu-latest' },
            { name: 'windows', image: 'windows-latest' },
            { name: 'macos', image: 'macos-latest' }
          ]

    runs-on: ${{ matrix.os.image }}

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Configure Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}

      - name: Install and build
        run: |
          npm ci
          npm run build
Enter fullscreen mode Exit fullscreen mode

Every job can provision databases for e2e tests with a services field like Postgres in the following example.

# .github/workflows/config.yml
jobs:
  build:
    name: Custom build job
    runs-on: ubuntu-latest

    strategy:
      matrix:
        database-name:
          - test-db
        database-user:
          - username
        database-password:
          - password
        database-host:
          - postgres
        database-port:
          - 5432

    services:
      postgres:
        image: postgres:latest
        env:
          POSTGRES_DB: ${{ matrix.database-name }}
          POSTGRES_USER: ${{ matrix.database-user }}
          POSTGRES_PASSWORD: ${{ matrix.database-password }}
        ports:
          - ${{ matrix.database-port }}:${{ matrix.database-port }}
        # Set health checks to wait until postgres has started
        options: --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      # ...
      - run: npm run test:e2e
        env:
          DATABASE_URL: postgres://${{ matrix.database-user }}:${{ matrix.database-password }}@${{ matrix.database-host }}:${{ matrix.database-port }}/${{ matrix.database-name }}
Enter fullscreen mode Exit fullscreen mode

Passing artifacts between jobs can be done with uploading (actions/upload-artifact) and downloading (actions/download-artifact) actions.

# .github/workflows/config.yml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Configure Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install and build
        run: |
          npm ci
          npm run build

      - name: Upload artifact
        uses: actions/upload-artifact@v3
        with:
          name: artifact
          path: public

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Download artifact
        uses: actions/download-artifact@v3
        with:
          name: artifact
      # ...
Enter fullscreen mode Exit fullscreen mode

Running locally

You can use act to run GitHub actions locally.

Install it and run it with the following commands.

curl -s https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
cp ./bin/act /usr/local/bin/act
act
Enter fullscreen mode Exit fullscreen mode

Top comments (0)