Releasing on GitHub Actions
I wanted to make a "CLI Tool" for orchestrating a "Website" deployment to a web host and I wanted to build and use this CLI tool in GitHub actions. GitHub has a ton of flexibility and features that should make both publishing the tool and deploying the website straightforward. This is the process I found that works for me.
Goals
- Manually initiate a production deploy of my website from main or a specific commit
- Tag the deploy with an auto incrementing version number
- Create a release with a change log
- Build and host the CLI on the cli's repo
- Download and use this cli on the website's repo
CLI Tool
The tool lets me deploy to a specific Render.com service. I've called it render-deploy
. I made it for fun. I need to build and host the cli and make it available to the other repository.
My first thought was a workflow artifact might be easiest to use, however these wont work for us;
- The artifacts only last a small number of days
- It's difficult to determine the latest build to download the files elsewhere
The next place you can attach files is in a github release.
Releases are deployable software iterations you can package and make available for a wider audience to download and use.
Which is perfect. You can create a release from a tag, attach files and provide change logs. Perfect. GitHub Actions has no release support built in and doesn't currently have an action for it. Currently ncipollo/release-action
seems to be the best supported and active action to create releases. If you give it a tag it will do the rest.
In order to create a tag I found mathieudutour/github-tag-action which borrows from @semantic-release/commit-analyzer
to manage your versions based on the commit messages. When run it will pull tags, analyze your commit messages and bump the version a patch, minor or major version. It can also generate a change log and even recommends ncipollo's release-action.
The commit analyzer looks for angular's commit message format which is basically type(scope): subject
. And you add BREAKING CHANGE:
two lines down if there is a breaking change. It's straightforward.
I landed on a workflow that builds and releases the main
branch, and bumps the tags as necessary.
name: Build and Release
on:
push:
branches: [ main ]
jobs:
build:
permissions: write-all
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
run: cargo test --verbose
- name: Build
run: cargo build --release
- name: 'Tar files'
run: tar -cvzf render-deploy-linux.tar.gz -C target/release render-deploy
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
path: ./render-deploy-linux.tar.gz
name: render-deploy-linux.tar.gz
- name: Bump version and push tag
id: tag_version
uses: mathieudutour/github-tag-action@v6.2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
fetch_all_tags: true
- name: Create a GitHub release
uses: ncipollo/release-action@v1
with:
tag: ${{ steps.tag_version.outputs.new_tag }}
name: Release ${{ steps.tag_version.outputs.new_tag }}
body: ${{ steps.tag_version.outputs.changelog }}
artifacts: ./render-deploy-linux.tar.gz
Every commit will be published as a new version which is fine for this use case.
Website
For the website I need to download the latest build of the cli tool, cut a release and then deploy.
The workflow_dispatch
trigger allows you to manually trigger workflows on a branch or commit. I used a "concurrency group" to ensure deploys happen in order and don't clobber eachother.
I found robinraju/release-downloader
which does what it says on the tin. I pointed it at the latest release on my CLI's repo and it downloaded the file by name. I had trouble with it's built in untaring but I bet with experimentation I could have gotten it to work.
mathieudutour/github-tag-action
was used again for tag management and ncipollo/release-action
was used again to create the release. The rest is fairly straightforward.
name: Production Deploy
run-name: Production Deploy
on:
workflow_dispatch:
concurrency:
group: deploy-production
cancel-in-progress: false
jobs:
deploy-production:
runs-on: ubuntu-latest
environment: Production
permissions: write-all
steps:
- name: Download Deploy Tool
uses: robinraju/release-downloader@v1
with:
repository: reconbot/render-deploy
latest: true
fileName: render-deploy-linux.tar.gz
- name: install deploy tool
run: tar -xvzf render-deploy-linux.tar.gz
- name: Bump version and push tag
id: tag_version
uses: mathieudutour/github-tag-action@v6.2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
fetch_all_tags: true
- name: Create a GitHub release
uses: ncipollo/release-action@v1
with:
tag: ${{ steps.tag_version.outputs.new_tag }}
name: Release ${{ steps.tag_version.outputs.new_tag }}
body: ${{ steps.tag_version.outputs.changelog }}
- name: Deploy Web
run: ./render-deploy -w production-remix-web
env:
RENDER_API_KEY: ${{ secrets.RENDER_API_KEY }}
- name: Deploy Worker
run: ./render-deploy -w production-remix-worker
env:
RENDER_API_KEY: ${{ secrets.RENDER_API_KEY }}
The only downside I've found is I don't always use angular's conventional commit messages for version control. And if you don't, you don't get any change log. I'm sure there's a way to list commits instead. Additionally I see that my use of Environments for secrets automatically creates Deployments. I'm not familiar with these features but it seems to provide a similar experience to releases but probably requires more configuration on my part.
Powered by ⚡️ and 🤖.