Posted on April 15, 2023 by Adrian Wyssmann ‐ 5 min read
Do you have multiple projects of the same topic, whicch use the same workflows? Then you might have a look into reusable workflows.
I have multiple ansible roles and I want to use the same workflows for all of these roles. This is when reusable workflows comes into play:
Rather than copying and pasting from one workflow to another, you can make workflows reusable. You and anyone with access to the reusable workflow can then call the reusable workflow from another workflow.
This consists of two elements:
Firs we are starting to create our shared workflow in a dedicate repository “github-actions-workflows”. The workflow are filed under the default path for workflows: .github/workflows/, e.g.
.github/workflows/ansible-roles-release.yml. In my case the workflow will do some linting, release preparation, creating and publishing the release (ansible role).
name: Create release
on:
workflow_call:
secrets:
gh_token:
required: true
galaxy_api_key:
required: true
jobs:
build:
name: Ansible linting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Lint Ansible Playbook
uses: ansible/ansible-lint-action@main
- name: Install Dependencies
run: pip install ansible
- name: Create ansible.cfg with correct roles_path
run: printf '[defaults]\nroles_path=../:./' >ansible.cfg
# - name: Run ansible syntax-check
# run: ansible-playbook tests/test.yml -i tests/inventory --syntax-check
prepare-release:
name: Prepare Release
runs-on: ubuntu-latest
steps:
- name: Set RELEASE_VERSION
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- uses: actions/checkout@v2
with:
ref: ${{ github.ref }}
fetch-depth: 0
- name: Create release branch
run: git checkout -b release/$RELEASE_VERSION && git push --set-upstream origin release/$RELEASE_VERSION
- name: Install auto-changelog
run: sudo npm install -g auto-changelog
- name: Set current version
run: echo $RELEASE_VERSION > ./VERSION
- name: Create changelog
run: auto-changelog --ignore-commit-pattern "^\[?ci|docu|Merge|meta\]?|fixup" --release-summary
- uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "meta: Update changelog, bump version"
file_pattern: ./VERSION ./CHANGELOG.md
commit_user_name: GitHub Actions
commit_user_email: [email protected]
commit_author: Papanito <[email protected]>
push_options: --force
create-release:
name: Create Release
runs-on: ubuntu-latest
steps:
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Checkout code
uses: actions/checkout@v2
- name: Install auto-changelog
run: sudo npm install -g auto-changelog
- name: Create release notes
run: auto-changelog --ignore-commit-pattern "^\[?ci|docu|Merge|meta\]?|fixup" --starting-version $RELEASE_VERSION -o RELEASENOTES.md --release-summary
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.gh_token }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body_path: ./RELEASENOTES.md
draft: false
prerelease: false
needs:
- build
- prepare-release
import-role:
runs-on: ubuntu-latest
needs: create-release
steps:
- name: Publish Ansible role to Galaxy
uses: hspaans/ansible-galaxy-action@v1
with:
api_key: ${{ secrets.galaxy_api_key }}As you can see there are two important things:
secrets (but also could define
inputs)secrets are reference accordingly in the steps like api_key: ${{ secrets.galaxy_api_key }}Workflows that call reusable workflows in the same organization or enterprise can use the inherit keyword to implicitly pass the secrets.
In the repositroy where you want to run the reusable workflow, you have to add the calling workflow under .github/workflows/, e.g.
.github/workflows/ansible-roles-release.yml.
name: Create release
on:
push:
tags:
- 'v*.*.*'
jobs:
call-workflow-passing-data:
uses: papanito/github-actions-workflows/.github/workflows/ansible-roles-release.yml@main
secrets:
gh_token: ${{ secrets.GITHUB_TOKEN }}
galaxy_api_key: ${{ secrets.ANSIBLE_GALAXY_APIKEY }}As part of the jobs you have to add call-workflow-passing-data.uses, which refers to the workflow which as to run, which is my ansible-roles-release.yaml on main-branch. I also pass the required secrets under secrets. Important is that these secrets (e.g GITHUB_TOKEN) are defined in the repository where the caller workflow is.
That’s all, pretty simple isn’t it, and indeed very helpful. However, keep in mind, there are certain limitations:
In order to deploy the caller workflow to all the repositories, I also use a
workflow publisher, which is stored under .github/workflows/workflow-publisher.yml of the repository “github-actions-workflows”. This job runs when changes are made to the calling workflow.
name: Workflow Publisher
on:
push:
branches: ['develop', 'main']
paths:
- 'ansible-roles/**'
workflow_dispatch:
jobs:
publish-workflow-template:
runs-on: ubuntu-latest
strategy:
matrix:
target_repo: [
'ansible-role-cloudflared',
'ansible-role-crowdsec',
'ansible-role-diskmounter',
'ansible-role-systemd_notifiers',
'ansible-role-ttrss',
'ansible-role-backup',
'ansible-role-git'
]
steps:
- name: Checkout source repo
uses: actions/checkout@v3
with:
path: main
- name: Checkout target repo
uses: actions/checkout@v3
with:
repository: ${{ github.repository_owner }}/${{ matrix.target_repo }}
path: ${{ matrix.target_repo }}
token: ${{ secrets.GH_TOKEN}}
ref: main
- name: Update workflows
shell: bash
run: |
mkdir -p .github/workflows/
cp ../main/ansible-roles/* .github/workflows/
working-directory: ./${{ matrix.target_repo }}
- name: Publish workflows
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "ci: update workflows"
commit_user_email: [email protected]
commit_user_name: GitHub Actions
repository: ./${{ matrix.target_repo }}
continue-on-error: false