Automatic gem release and tag after changing version

I’ve been playing with GitHub actions the past few days, mainly focusing on gem release automation.

My goal was simple: Releasing plugins takes too much time, too many steps and it’s boring. So it’s a perfect candidate for automation.

In the ideal state, I as a developer want to just change the version file and automation will do the rest. One direct commit to the main branch, that’s all.

Steps in detail:

  • Run the job when version.rb is changed
  • Get the version from the file (let’s say 1.2.3)
  • Build foreman_plugin-1.2.3.gem
  • Push it to rubygems.org
  • Create tag v1.2.3 in the plugin repository.

I have POC GitHub action for my simple test gem, it’s basically ready for use in our plugin repos with a tiny change, and that is for the actual gem build we can use “our” action from the theforeman/actions repository.

Action breakdown

Watch file changes

on:
  push:
    paths:
      - "lib/version.rb"

Get plugin version

      - name: Set variables
        run: |
          VER=$(bundle exec ruby -e 'puts Hola::VERSION')
          echo "VERSION=$VER" >> $GITHUB_ENV

Create tag
(For this secrets.GITHUB_TOKEN needs write permissions to repo)

      - name: Tag snapshot
        uses: tvdias/github-tagger@v0.0.1
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          tag: "v${{ env.VERSION }}"

Publish gem (will be replaced by our action)

      - name: publish gem
        run: |
          mkdir -p $HOME/.gem
          touch $HOME/.gem/credentials
          chmod 0600 $HOME/.gem/credentials
          printf -- "---\n:rubygems_api_key: ${RUBYGEM_API_KEY}\n" > $HOME/.gem/credentials
          gem build *.gemspec
          gem push *.gem

Full file


What do you think?

In upcoming weeks I’m going to configure it for the foreman_ansible, foreman_puppet, and other plugins under our team, but I’d like to know if other plugin maintainers would be interested in it and if we could potentially make it across the whole theforeman org plugin ecosystem.

3 Likes

Have you looked at:

I assume you do since you reference theforeman/actions. It feels like this is taking it a step further to also create the tag. I’ve mentally played with the same concept, but never got around to implementing it.

In the past I’ve played around with bump2version · PyPI to automate how to bump. With that it’s actually pretty trivial. Now I must admit that these days I don’t have time to contribute to bump2version anymore and perhaps there are better solutions, but it’s nice to somehow abstract it.

One benefit of manual tags that I do like (but don’t really benefit from today) is GPG signed git tags. Another thing to consider in all of this is that we can’t use 2FA on our releases today. Tim mentioned the other day they are looking into it (on Rubygems).

What we use in our translations (and is more generic):

Or more minimal:

ruby -rrubygems -e 'puts Gem::Specification::load(Dir.glob("*.gemspec")[0]).version'
1 Like

+1 for any automation!

I would lean more toward adding plugins to nightlies which can help to reduce the release work for some plugins, for example, those that release every week or less than a week.

Though to verify that the packaging is stable, I would recommend doing a version bump / pre-release on 3 weeks cadence.

Is it worth looking into how Pulp plugins do this? (Every Pulp plugin has a release workflow that creates branches tags, etc. and once a tag is created, everything is automatically pushed to rubygems.org and pypi.org.

For example, all the gems here: pulp_deb_client | RubyGems.org | your community gem host
Were built by pipeline triggered here: Actions · pulp/pulp_deb · GitHub