Reusing Workflows GitHub Actions
Promoting DRY(Don't Repeat Yourself) principle, reusing the GitHub actions workflows, making your CI/CD pipelines more manageable.
Overview
GitHub Actions' reusable workflows enable you to avoid duplicating code by creating a workflow that can be invoked from other workflows. This is great for promoting the "Don't Repeat Yourself" (DRY) principle, maintaining consistency across projects, and making your CI/CD pipelines more manageable.
Create Reusable Workflow
The reusable workflows are essentially a set of YAML files, similar to other GitHub Actions workflows. The reusable workflows can be part of the same repository or added to a different repository. The reusable workflows are triggered with on.workflow_call event.
Let’s now create a workflow that would be called in another GitHub Actions workflow.
Reusable Workflow - Test node app
name: test-node-app
on:
workflow_call:
secrets:
CODACY_PROJECT_TOKEN:
required: true
jobs:
test-node-app:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 20.x ]
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test -- --coverage
- name: Archive coverage data
uses: actions/upload-artifact@v4.0.0
with:
name: jest-coverage-data
path: ./coverage
- name: Run codacy-coverage-reporter
uses: codacy/codacy-coverage-reporter-action@v1.3.0
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
coverage-reports: ./coverage/lcov.info
The workflow above would run the test coverage for the Node.js application and publish the coverage report to Codacy. The workflow accepts one secret as a parameter to be passed while calling from another workflow. As mentioned above, the workflow would be triggered on the workflow_call event.
Call Reusable workflow - Main Workflow
Now let’s add the main workflow, which builds, tests, and publishes a Docker image for the NodeJS app. This workflow would call the reusable test-node-app workflow as mentioned above.
Main Workflow - node app
name: Node.js CI
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 20.x ]
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm run build --if-present
test:
uses: ./.github/workflows/test-node-app.yml
secrets:
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
publish:
runs-on: ubuntu-latest
needs: [ build,test ]
steps:
- name: Check out the repo
uses: actions/checkout@v4
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Docker build and push
uses: docker/build-push-action@v2
with:
context: .
push: 'true'
tags: abc/your-app:latest, abc/your-app:${{ github.run_number }}
As mentioned in the workflow, the test job calls the reusable workflow test-node-app. The workflow executes the build and test jobs in parallel, then builds and publishes the Docker image to Docker Hub.
See below the sample execution of the main workflow
Conclusion
Reusable workflows provides flexiblity of reusing GitHub Actions' workflows and avoid duplicating code by creating a workflow that can be called from other workflow. Reusable workflows are ideal for complex, multi-job processes like CI/CD pipelines.