Since that was such a straight-forward post, this will be more on the adjustments made to my own project to also automate the Ruby Gem release.
The method we are going to take makes use of Google's GitHub Action release-please-action. This action takes your commit history to help automate the package semantic version.
If you are not familiar with conventional commits, the quick summary gives a good overview of how it works.
Essentially, you prefix your git commits with a specified "type" and "optional scope" <type>[optional scope]: <description> and based on the type, it will have a different weight for the impact on the versioning.
The types fix and feat are associated with PATCH and MINOR updates respectively, while a BREAKING CHANGE or bang following the type <type>! will result in a major change.
If you look at the history of the logs I have committed for this project, you will see the following (using git log --pretty=oneline):
$ git log --pretty=oneline
0e0977aa (HEAD -> main, origin/main, origin/3-gem-deployed, 3-gem-deployed) feat: add the example folder
012bdeb7 (origin/2-gemspec, 2-gemspec) feat: add in gemspec file
3e0f797b (origin/1-rspec-with-github-actions, 1-rspec-with-github-actions) fix: README
d5fd59c2 fix: remove lcov
f639002d docs: add README
016d5ae7 feat: first attempt at post
Luckily, this bodes well for our GitHub Action.
Updating our GitHub Workflows
Let's make some adjustments to our .github/workflows/rspec.yml workflow:
name: Run RSpec tests
on:
push:
branches:
- "**" # matches every branch
- "!main" # excludes main
jobs:
run-rspec-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
# Not needed with a .ruby-version file
ruby-version: 2.7
# runs 'bundle install' and caches installed gems automatically
bundler-cache: true
- name: Run tests
run: |
bundle exec rspec
This will not run the RSpec tests action on the main branch, which we will set up a new action for.
Next, let's create a new workflow. Create a new file with touch .github/workflows/release.yml and then add the following code:
name: Release
on:
push:
branches:
- "main" # main only
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: GoogleCloudPlatform/release-please-action@v2
id: release
with:
release-type: ruby
package-name: contrived_math
bump-minor-pre-major: true
version-file: "lib/release/contrived_math/version.rb"
# Checkout code if release was created
- uses: actions/checkout@v2
if: ${{ steps.release.outputs.release_created }}
# Setup ruby if a release was created
- uses: ruby/setup-ruby@v1
with:
# Not needed with a .ruby-version file
ruby-version: 2.7
# runs 'bundle install' and caches installed gems automatically
bundler-cache: true
if: ${{ steps.release.outputs.release_created }}
- name: Run tests
run: |
bundle exec rspec
if: ${{ steps.release.outputs.release_created }}
# Publish
- name: publish gem
run: |
mkdir -p $HOME/.gem
touch $HOME/.gem/credentials
chmod 0600 $HOME/.gem/credentials
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
gem build *.gemspec
gem push *.gem
env:
# Make sure to update the secret name
# if yours isn't named RUBYGEMS_AUTH_TOKEN
GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
if: ${{ steps.release.outputs.release_created }}
This new action will run on main and will release our Ruby Gem if both testing and the release-action-please succeed.
This example is contrived and will only run things on the main branch, but adjust this for the release workflow you actually want in your own work.
Note: you will need to create a new RubyGems API key and add that to the repo as the secret named RUBYGEMS_AUTH_TOKEN.
Configuring our version for our gemspec file
Update contrived_math.gemspec to the following:
require_relative 'lib/release/contrived_math/version'
Gem::Specification.new do |s|
s.name = 'contrived_math'
s.version = ContrivedMath::VERSION
s.summary = 'Hello, World!'
s.description = 'A simple hello world gem'
s.authors = ["Dennis O'Keeffe"]
s.email = 'hello@dennisokeeffe.com'
s.files = ['lib/contrived_math.rb']
s.homepage =
'https://rubygems.org/gems/contrived_math'
s.license = 'MIT'
end
Now we will grab the version from the file lib/release/contrived_math/version.rb.
Assuming you already set up the secret for the RubyGems, we can push main and see the action at work.
New action running
The first time we run the action, it will note that it needs to create a release PR for us. We can see that in the action logs.
Action creating a release
This release will create some release notes and a PR. The notes will followed the conventional commit types.
Release notes created
Created PR
Next, we can approve and merge the PR.
PR approval
Once merged, the bot will link the release notes for us.
PR merged and release notes added
The merge of the pull request will kick off another invocation of the release action. This time, the action will release the gem.
Note: The 0.1.0 release failed because I was a goose, so the following two images come from the 0.1.1 release which followed all the same previous steps after I implemented the fix.
Release action workflow running
Finally, a successful release will also show up on our live Ruby Gem.
The RubyGem release
Success! The release schedule has been automated through GitHub Actions.
Summary
Today's post demonstrated how to take our Ruby Gem repo and automate the release process based on changes noted in git history using Conventional Commits.
It is worth noting that these flows outlined today may not be appropriate to your own needs (I am only running release on the main branch will generally is not what you will want since main would be protected), but take the workflows from today and apply the changes for your own work as required.