Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What would an auto-release workflow look like? #117

Open
epage opened this issue Jun 3, 2019 · 10 comments
Open

What would an auto-release workflow look like? #117

epage opened this issue Jun 3, 2019 · 10 comments
Labels
question Uncertainty is involved

Comments

@epage
Copy link
Collaborator

epage commented Jun 3, 2019

Something I've been considering is the idea of auto-releasing after each PR but the question is "how?"

  • Determine bump level
  • Ensure we don't get into an infinite loop (a release causes a commit which causes a release)
  • Any changelist management?
@epage epage added the question Uncertainty is involved label Jun 3, 2019
@epage
Copy link
Collaborator Author

epage commented Jun 3, 2019

One approach I just came across via awesome-rust is semantic which uses clog to generate the changelog and determine the bump level based on the commit messages.

@sunng87
Copy link
Collaborator

sunng87 commented Jun 4, 2019

Personally I prefer an isolation between commit log, which is dev-facing, and release notes, which is user facing. So I didn't included auto changelog generation from very beginning.

However, I agree it's possible to determine the release level from commit log or public api changes. I wish semantic could offer a binary of library just for determining bump level so we can add optional support for that.

@epage
Copy link
Collaborator Author

epage commented Jun 4, 2019

Personally I prefer an isolation between commit log, which is dev-facing, and release notes, which is user facing. So I didn't included auto changelog generation from very beginning.

Ideally, yes but I maintain too many crates to always worry about the changelog. Maybe switching to cargo-release will help. However, I do tend to make my commits more user focused (if they are feat/fix rather than refactor/chore).

And too often I see projects, major projects, without them and I'm at a loss digging through commits when they make breaking changes. Something is better than nothing.

However, I agree it's possible to determine the release level from commit log or public api changes. I wish semantic could offer a binary of library just for determining bump level so we can add optional support for that.

At my quick glance, it looked like semantic was just calling into clog-cli's crate to see if anything was considered breaking from conventional-changelog's perspective, so that should be relatively easy to pull out.

@epage
Copy link
Collaborator Author

epage commented Jun 4, 2019

The downside to semantic's approach is you have to hope you did things right for it to correctly guess what version field to bump. If you mess up, you might end up needing to yank a release. I have also found that while it is easy to get people to do checklist tasks in the source code (like update changelog), it is harder to be programmatically precise tasks like with commit messages.

Another approach is to instead have the source always represent what the next version will be. If a commit makes a breaking change, then that commit is responsible for updating the version number without doing a release. The CI then releases that version. To support this, we might want a --no-release flag that is a shortcut for --no-push, --no-tag, etc that a developer will call in prep for their PR.

The use cases we'd want to consider supporting

  • Dev bumps minor, major with or without pre-release
    • --no-release would help
    • It'd be nice to have a way to a bump to a pre-release major or minor
  • The CI releases the current version
    • We'd need a new level: unchanged
  • Post-release, the CI bumps the version to be a patch or an incremented pre-release, depending on the project's config
    • We'd want a post-level arg.
      • For projects that only want automatic pre-release versions, they can use the existing pre-release levels
      • For projects that don't normally use pre-release, they might want a increment level that increments pre-release, if present, and otherwise increments patch.

... I have more thoughts and there is some problem areas but I wanted to post this without a long delay as I write it all up

@TomPridham
Copy link

we recently did this at my work and i figured it would be helpful to share since it was not straight forward to figure out. the workflow we have relies on two main actions, one to ensure that pr titles(and thus the merge commit) have a valid bump level and one that reads that commit and creates the tag and bumps everything.

a MAJOR caveat with this is that adding those secrets makes them available for use by anyone opening a pr on your repo. if you google "push to protected branch github action", you will get a bunch of results like this: https://github.community/t/allowing-github-actions-bot-to-push-to-protected-branch/16536 . we are using this on a private repo, so we're not really concerned with someone doing some fishy. i think there must be ways to mitigate that since rust itself has something like this, but i haven't looked into it at all

name: Check PR Title

on:
  pull_request:
    types: [opened, edited, synchronize, reopened]

jobs:
  check-pr-title:
    runs-on: ubuntu-latest
    steps:
      - uses: deepakputhraya/action-pr-title@master
        with:
          allowed_prefixes: "#major,#minor,#patch,#none" # title should start with the given prefix
          prefix_case_sensitive: false # title prefix are case insensitive
          github_token: ${{ github.token }} # Default: ${{ github.token }}
name: Bump version, create new tag and release point
on:
  push:
    branches:
      - "main"

jobs:
  bump_version:
    name: Bump version, create tag/release point
    runs-on: ubuntu-latest
    # prevent recursively starting actions. it will only start one extra and then fail on the
    # `bump_version` step if it is removed, but it's good to have for other github actions that
    # might trigger on pushes to main
    if: "!startsWith(github.event.head_commit.message, '[RELEASE]')"
    steps:
      # cache cargo release so we don't have to install it every time
      - name: Cache cargo release and rust install steps
        id: cache-release
        uses: actions/cache@v2
        with:
          path: |
            ~/.cargo/bin/
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            ~/target/
          key: ${{ runner.os }}-cargo-release

      - name: Checkout code
        uses: actions/checkout@v2
        with:
          repository: pdq/rover
          # if you have branch protection on, you will need to a secret PAT for a repo admin or add
          # an exception for user who generated the PAT
          # this action caches the authentication it uses and makes that the default for future
          # steps. adding the token here means you don't have to add it manually in a later step
          token: ${{ secrets.PAT_GIT_BOT }}
          fetch-depth: "0"

      - name: Import GPG key
        uses: crazy-max/ghaction-import-gpg@v4
        with:
          # if you are requiring signed commits, you need to add a secret private key that will be
          # used to sign the commits/tags
          gpg_private_key: ${{ secrets.GPG_RSA_PRIVATE_KEY }}
          git_user_signingkey: true
          git_commit_gpgsign: true

        # this is an easy way to get the bump level from the pr title once it has been merged. it
        # makes the bump level available to use in the cargo release step
      - name: Get version from PR
        id: bump_version
        uses: anothrNick/github-tag-action@1.36.0
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          WITH_V: false
          DEFAULT_BUMP: none
          DRY_RUN: true

      - name: install cargo-release
        uses: actions-rs/cargo@v1
        if: steps.cache-release.outputs.cache-hit != 'true'
        with:
          command: install
          args: cargo-release

      - name: Setup Git info
        run: |
          git config user.name "git-bot"
          git config user.email "git-bot@your-domain.com"

      - name: Create tag and update Cargo.toml
        uses: actions-rs/cargo@v1
        with:
          command: release
          args: ${{ steps.bump_version.outputs.part }} --execute --no-confirm

@petersooley
Copy link

For what it's worth, if you don't need signed commits or are worried about protected branches, you can get away with a much more out-of-the-box release process.

name: Release

env:
  CARGO_TERM_COLOR: always

defaults:
  run:
    shell: bash

on:
  workflow_dispatch:
    inputs:
      level:
        type: choice
        description: Bump level
        options:
          - patch
          - minor
          - major

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - name: cache cargo cache
        id: cache-release
        uses: actions/cache@v2
        with:
          path: |
            ~/.cargo/bin/
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            ~/target/
          key: ${{ runner.os }}-cargo-release

      - name: checkout code
        uses: actions/checkout@v3
      
      - name: git config
        run: |
          git config user.name "Github Actions: Release"
          git config user.email "<>"

      # fail early if tests fail
      - name: run tests
        run: |
          make test

      - name: install cargo-release
        uses: actions-rs/cargo@v1
        if: steps.cache-release.outputs.cache-hit != 'true'
        with:
          command: install
          args: cargo-release

      - name: cargo release ${{ github.event.inputs.level }}
        uses: actions-rs/cargo@v1
        with:
          command: release
          args: ${{ github.event.inputs.level }} --execute --no-confirm --config .github/workflows/cargo-release.toml

@epage
Copy link
Collaborator Author

epage commented Oct 21, 2022

With 0.22 out, we now have cargo release --unpublished which would allow CI to automatically release crates if a commit is pushed/merged with the version fields changed.

While this isn't fully automatic, this gets as close as I think is safe at this point.

@thomaseizinger
Copy link

thomaseizinger commented Mar 8, 2023

I've started building a tool that I called semverlog. The idea is to eventually have one-click style releases.

semverlog has a compute-bump-level command which will look for a .changes directory in the current working dir and print "major", "minor" or "patch" to stdout, based on the changes found.

I was envisioning the following integration with cargo release:

cargo release version --level-from-command="semverlog compute-bump-level"

cargo release already figures out which dependencies to release in which order in a workspace. To compute the level, it would execute the given command with the crate-to-be-released as the working directory.

What do you think of this idea?

@epage
Copy link
Collaborator Author

epage commented Mar 9, 2023

I can't fully articulate why but that handshake doesn't feel quite right to me.

@thomaseizinger
Copy link

I can't fully articulate why but that handshake doesn't feel quite right to me.

Do you see any possible integration that would compute the bump level dynamically?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Uncertainty is involved
Projects
None yet
Development

No branches or pull requests

5 participants