Skip to content

Release pipeline automation

Marc Busqué edited this page Dec 23, 2022 · 10 revisions

The Solidus repository at solidusio/solidus relies on a series of automation to streamline the processes related to delivering new versions.


Most of the integrations are controlled by labels on Pull Requests. For this reason, we need to be very careful before renaming or deleting them.


Triaging

All submitted PRs get assigned a label that identifies which gem the changes belong to:

  • changelog:solidus_core
  • changelog:solidus_backend
  • changelog:solidus_api
  • changelog:solidus_sample
  • changelog:solidus
  • changelog:repository: identifies updates that don't belong to any gem.

The triage is automatically done by the "Triage for Changelog" workflow by checking the files modified on a PR. On top of that, the "Ensure Changelog label" workflow fails if none of those labels is present.

Eventually, the information will be leveraged to create the release notes and update the Changelog. The changelog:skip label can be manually applied to skip a PR from that downstream automation.

Release notes drafting

Whenever a PR is merged, their changelog labels are used to add a new entry in the GitHub release draft for the next version.

That's done by the "Update Release Draft on GitHub" workflow.


As the release notes are automatically generated, we must avoid manually updating them.


Preparing a release

When the time comes to release a new Solidus version, we can manually dispatch the "Prepare release" workflow. As the GitHub documentation explains, there're different ways of doing that.

To prepare a new release from GitHub's UI, navigate to the "Actions" tab and select the "Prepare release" item.

screenshot-github com-2022 12 23-05_04_40

After that, click on the "Run workflow" dropdown. It'll prompt you to select the branch from which the release needs to be prepared and whether it is the next-to-last after a major release.

screenshot-github com-2022 12 23-05_14_10

Alternatively, the most straightforward way to run the workflow from the command line is through GitHub's CLI tool:

# Prepare a release on master
gh workflow run prepare_release.yml

# Prepare a release on master for the previous release after the last minor in a series
gh workflow run prepare_release.yml -F last_minor=true

# Prepare a release for v3.2
gh workflow run prepare_release.yml --ref v3.2

Once the automation is run, a new PR for the picked branch will be ready with the following:

  • References to the current Solidus version bumped to the release candidate one.
  • Updated Changelog with the contents of the corresponding release notes.

The created PR will contain the release:generate label and the release:generate-last_minor one in case the corresponding checkbox has been checked. Those labels will be used to perform the after-release chores.

It's worth noting that the release to RubyGems is not covered, so security is not compromised. That step still needs to be manually done through the gem release command provided by the gem-release gem.

Performing after-release chores

Once a PR preparing a release is merged, a new PR is created, automating the post-release chores:

  • Bumping version to the next candidate .dev one.
  • Publishing the release draft and tagging the last commit accordingly.
  • Creating a new v* branch for releases on master (minor and major releases).

That's coordinated thanks to the "Prepare post-release" workflow.

Extracting pipeline information

Most of the automation mentioned above needs information about the active pipeline, e.g., the current version, the candidate tag, etc. That's orchestrated by the "Extract Pipeline Context" composite action. We can summarize its work:

  • The most recent tag is extracted from the list of tags in the repository:
    • For master, that's going to be the higher one.
    • For v* branches, that will be the higher one for the branch.
  • For the to-be-released candidate:
    • For master:
      • It's one minor level higher than the current tag when Spree::VERSION doesn't track a major release.
      • It's one major level higher than the current tag when Spree::VERSION tracks a major release.
    • For v* branches, it's one patch level higher than the current tag.
  • For the next to-be-released candidate (only used to prepare the after-release chores):
    • For master:
      • It's one minor level higher than the candidate tag when we don't specify that a candidate will be the last minor release (see how to prepare a release).
      • It's one major level higher than the current tag when we specify that a candidate till be the last minor release.
    • For v* branches, it's one patch level higher than the to-be-released tag.

Diagram

flowchart LR
  Contributor("USER")
  Maintainer("MAINTAINER")
  TriageWorkflow("WORKFLOW: Triage")
  EnsureLabelWorkflow("WORKFLOW: Ensure Label")
  PrepareReleaseWorkflow("WORKFLOW: Prepare release")
  PreparePostReleaseWorkflow("WORKFLOW: Prepare post-release")
  Contributor-->ContributionPR
  Maintainer-->PrepareReleasePR
  ContributionPR --> TriageWorkflow --> EnsureLabelWorkflow --> Draft
  PrepareReleasePR --> PrepareReleaseWorkflow --> PreparePostReleasePR
  PreparePostReleasePR --> PreparePostReleaseWorkflow
  PrepareReleaseWorkflow <--> Draft
  PreparePostReleaseWorkflow --> Tag
  PreparePostReleaseWorkflow -- master? --> Branch
  PreparePostReleaseWorkflow -- publish --> Draft
  subgraph "Pull requests"
    PrepareReleasePR("PR: Prepare release (changelog:skip, release:generate)")
    PreparePostReleasePR("PR: Prepare post-release")
    ContributionPR("PR: Contribution (changelog:solidus_core)")
  end
  subgraph "Release notes"
    Draft("Draft")
  end
  subgraph "Tags"
    Tag("Tag")
  end
  subgraph "Branches"
    Branch("Branch")
  end
Loading