Github actions release workflow

Posted in development on August 3, 2020 by Adrian Wyssmann ‐ 5 min read

Even so I mostly use Gitlab, I am also active in Github, especially also for the ansible roles which I host in GIthub - just cause everything related to ansible can also be found there.

Since I provide my ansible roles in github, I thought it would be nice to have a proper release workflow with Github Actions. My goal was the following

  • trigger a new release by tagging the code
  • update VERSION-file
  • update the changelog
  • create a release
  • import the role to ansible-galaxy

First you have to place a yaml-file to ./.github/workflow, I name mine release.yaml - the name does not really matter.

trigger a new release by tagging the code

This is straight forward, as I can define this in the pipeline

on:
  push:
    tags:
      - 'v*.*.*'

So the workflow can be triggered as follows

git tag <tag name>
git push --tags

update VERSION-file

Usually the version information - for ansible roles it’s the VERSION-file should be updated before you create a release and before you import the role into ansible-galaxy. Thus I want that automated and using the same version as from the tagging operation. Thus I store the release version in a variable and use it later

- name: Set env
run: echo ::set-env name=RELEASE_VERSION::${GITHUB_REF#refs/*/}
- name: Set current version
run: echo $RELEASE_VERSION > ./VERSION

Update the changelog

Instead of manually creating and committing the changelog, I want this automated. I looked into different implementations and finally decided to use auto-changelog which works quite nice.

So I have to first install the npm package

- name: Install auto-changelog
  run: sudo npm install -g auto-changelog

Then I can use it in the pipeline to create the CHANGELOG.md. I only want commits which contains features and bug fixes, not changes of metadata or ci. Thus I usually add something like [meta] or [ci] as prefix of the commit message to distinct the type of commit. Thus I can ignore such commit messages quite easy

- name: Create changelog
  run: auto-changelog --ignore-commit-pattern "\[ci|docu|meta\]|fixup"

Committing changes

As there are changes in the VERSION and CHANGELOG.md I will commit this changes and also update the tag so it points to this commit. For that purpose I have to create a release-branch as otherwise committing changes will simply be lost.

- name: Create release branch
  run: git checkout -b release/$RELEASE_VERSION &&  git push --set-upstream origin release/$RELEASE_VERSION

I found the git-auto-commit-action to commits files which have been changed during a Workflow run and pushes the commit back to GitHub:

- uses: stefanzweifel/git-auto-commit-action@v4
with:
    commit_message: "[meta] Update changelog, bump version"
    file_pattern: ./VERSION ./CHANGELOG.md
    commit_user_name: My GitHub Actions Bot
    commit_user_email: [email protected]
    commit_author: Papanito <[email protected]>
    push_options: --force
Update changelog, bump version

create a release

To create a proper release incl. release notes is easily done with create-release action. I dynamically create the RELEASENOTES.md which provides the content for the particular release. The difference to the CHANGELOG.md is that it only contains the diff between the previous and the current tag, plus the file will not be committed. I use the same auto-changelog from above.

- name: Create release notes
  run: auto-changelog --ignore-commit-pattern "\[ci|docu|meta\]|fixup" --starting-version $RELEASE_VERSION --hide-credit -o RELEASENOTES.md

Once I have the RELEASENOTES.md I can create the release using the $RELEASE_VERSION and body_path: ./RELEASENOTES.md:

- name: Create Release
    id: create_release
    uses: actions/create-release@v1
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_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

import the role to ansible-galaxy

As a last step, the role is imported into ansible-galaxy using the galaxy-role-import-action

- uses: 0x022b/galaxy-role-import-action@v1
  with:
    galaxy_api_key: ${{ secrets.ansible_galaxy_apikey }}

Merge changes

As there is a separate release branch I will have to merge it back to master-branch. I guess that’s not bad as it let me review the changes.

Bring it all together

At final the file release.yml looks something like this

name: Create release

on:
  push:
    tags:
      - 'v*.*.*'

jobs:
  build:
    name: Ansible linting
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Lint Ansible Playbook
      uses: ansible/ansible-lint-action@master
      with:
        targets: "**/*.yml"
    - 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 env
        run: echo ::set-env name=RELEASE_VERSION::${GITHUB_REF#refs/*/}
      - 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|meta\]|fixup"
      - uses: stefanzweifel/git-auto-commit-action@v4
        with:
          commit_message: "[meta] Update changelog, bump version"
          file_pattern: ./VERSION ./CHANGELOG.md
          commit_user_name: My GitHub Actions Bot
          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 ::set-env name=RELEASE_VERSION::${GITHUB_REF#refs/*/}
      - 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|meta\]|fixup" --starting-version $RELEASE_VERSION --hide-credit -o RELEASENOTES.md
      - name: Create Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_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: falsemenu:
  docs:
    parent: "aboutus"
  projects:
    parent: "aboutus"
          prerelease: false
    needs: 
    - build
    - prepare-release

  import-role:
    runs-on: ubuntu-latest
    needs: create-release
    steps: 
    - uses: 0x022b/galaxy-role-import-action@v1
      with:
        galaxy_api_key: ${{ secrets.ansible_galaxy_apikey }}

The workflow covers the basic, straight forward release process and avoids manual steps where possible. There is for sure things to improve, but for now it does it’s job very well.