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

ci: release process document #2153

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions tools/scripts/release/RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@

# Current Process

Steps:

- Create a release branch
- Enumerate per-crate incoming Changelog entries
- Create a release plan (list of crates to be published, in dependency order)
- Increment version number for changed crates and crates with changed dependencies.
- Update READMEs
- Update dependency versions in Cargo.toml
- Integrate incoming Changelog entries into existing Changelogs
- Merge to develop
- Merge to main
- `cargo publish` crates in dependency order
- `gh release` crates. Release `ockam` crate last.

Details:

### Incoming Changes

To find what has changed between releases for each crate, I use a script that parses `git log` output.

New files named `Changelog-INCOMING.md` are created for each crate. This file has a header that has the correct version, date, and header structure. Below the header is a list of commit messages that affected the crate.

I review the list of commits and copy/paste the `feat`, `fix` and other relevant changes into the appropriate section (Added, Changed, Removed). We do not include doc or test entries, only important changes.

After the new Changelog entry is ready, it is cut and paste into the real `Changelog.md` for the crate.

### Version increments

Prior to workspaces, I was able to use the `cargo bump` utility to manage version increments, but that it doesn't work with workspaces.

Now I manually increase the version number in `Cargo.toml` for each crate that requires a release.

The version needs to be increased IF:

- There is any change listed in the `Changelog-INCOMING.md`
- There is a version bump of an internal crate dependency.

When we begin using patch releases, this is an opportunity to determine the 'size' of the bump..minor vs patch, informed by the entries in the Changelog.

### Update READMEs and Cargo.toml dependencies

A script performs a find and replace in `README`s and and dependants `Cargo.toml` to bump the crate version to the new version.

### Merge to Develop and Main

A PR is created for the release branch, passes CI and is merged to `develop`.

A PR is created for the release branch, passes CI and is merged to `main`.

### cargo publish

After the release PR has been merged to `main`, A `cargo publish` is done for each crate, in dependency order.

The timing of this process can be tricky since there is a delay between a successful `cargo publish` and the time the artifact is available in the crate index. Attempting to publish a crate too quickly before its dependencies are available will cause an error.

### gh release

I run `gh release` for each crate. The command creates tags, pushes them, then creates a GitHub release using the standard template for the description.

The `ockam` crate is released last, so that it is the last visible release listed on the GitHub website.

# New Process

Steps:

- Create a release branch
- Add `Unreleased` section to each crate `Changelog.md` which lists incoming changes.
- Set the `TOKEN` env var to a crates.io API token with publish rights
- Set the `UPSTREAM` env var to a branch to diff against
- Run `crate-publisher.sh` script


### crate-publisher steps

Steps that the `crate-publisher.sh` script performs:

- Ensure upstream branch exists
- Install `cargo release` if needed
- Determine what crates have changed by using `git diff` against `UPSTREAM`
- For each changed crate:
- Run `cargo release minor --skip-tag --skip-push --skip-publish --no-dev-version --execute`
- Run `git reset` to `HEAD`
- Run `git add --all`
- Run `git commit -m "committed all crates"`
Comment on lines +83 to +87
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not using git commands for bumps
https://github.com/ockam-network/ockam/blob/30f44e51017b8e3d10a0fba7b49c7fc606ed58fa/tools/scripts/release/crate-publisher.sh#L108

  • ^cargo release is called for all crates so as to bump their versions and also dependencies.

https://github.com/ockam-network/ockam/blob/30f44e51017b8e3d10a0fba7b49c7fc606ed58fa/tools/scripts/release/crate-publisher.sh#L110-L116

  • ^ If a cargo release command fails for a specific crate, the script then resets all changes that were made and pauses so that we can debug the failing crate that is to be released and then continue with deployment or abort.

- Run `git reset HEAD` again
- Prints "cargo release commits squashed" ?
- Pause and prompt user to verify `git diff`
- Run `git add --all` again
- Run `git commit` again
Comment on lines +88 to +92
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be improved, my initial assumption was that cargo release doesn't allow us exclude crates over cli, apparently I was wrong. I believe we can call cargo release with the workspace feature link here (exclude field), we can get crates that are to be excluded using our Changelog script and then indicate to cargo release crates that should not be released.

- FORCE PUSH to current branch: `git push --set-upstream origin "$current_branch" -f`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more of

  • Will the user create a new branch which this script will be called on?
  • Will the branch be published upstream?
  • Will there be conflicts on the branch?

- Pause and print `Commits pushed upstream, please merge and press enter to start git tagging`
- For each changed crate:
- Get current crate version via the changelog (?)
- Run `gh release create`
- For each changed crate:
- Get current crate version via the changelog (again)
- Run `cargo publish`
- Run `cargo search` until published crate appears.


# Concerns

## Logical concerns

### Too many git operations
- The critical steps that this process needs to accomplish are:
- Version increment crate `Cargo.toml` for changed crates
- Find and replace new version in `README`s
- Update interdependencies in crates' `Cargo.toml`

These are all simple text manipulation tasks. None of this should require so many git calls.
Comment on lines +109 to +114
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


### Using diff from main instead of finding last tags

- This process relies on the fact that main and develop diverge between releases, and compares them to find the differences.
- It is more accurate to find the commit hash of the last crate tagging. Since currently all tags happen at the same time, this is a single commit.
- If for some reason `main` diverges for non-release reason, such as maintenance or bug fixes, this could cause problems
Comment on lines +116 to +120
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love this. I totally agree with this, I believe we can make the current script better and leaner.


### Using the Changelog version as the source for version info

We should not rely on Changelog for the accuracy of the crate version. The crate version should come from `Cargo.toml`, where we _know_ it is accurate. If the version is wrong in `Cargo.toml`, it is apparent and things will break. If the version is wrong in the Changelog, the script will just use it and believe it.

The Changelog is metadata for humans, tooling should not rely on it.
Comment on lines +122 to +126
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯 we shouldn't use the Changelog as the source of truth.


### Publishing to GitHub before crates.io

It is more liklely that things will go wrong when performing `cargo publish` than to releasing GitHub. For this reason, it's important that we successfully publish to crates.io before we publish to GitHub, or we risk publishing a bad release.

I have many times only discovered problems with a crate after it has been rejected by `cargo publish`.

### Static list of crates

- This release process requires a static list of crates embedded in the script, which has already become outdated.
- Should not be necessary: we know exactly what our list of crates is from our repo directory structure.
- Instead we should have a way to omit crates that we do not want to publish (if any) for example the `ockam_examples`
- Further more, this static list must be ordered by internal dependencies, and is currently incorrect.
- Internal dependencies can and do change often. This is hard to maintain.
Comment on lines +134 to +140
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Jared. This was a concern for me we should be able to solve this using cargo release.


## General script concerns

- Relative directories are used too much. See the existing scripts strategies of utilizing an `$OCKAM_HOME` variable, which can be used as the base to define other locations.
- Use `pushd` and `popd` to manage directory state instead of `cd`
- Remove all `$(tput setaf 2)` and `$(tput sgr0)` from message lines. They add too much noise and obscure what is going on.
- Consider making a function named something like `print_message` which injects these colors, if necessary.
- The presence of `gh` is assumed but not checked
Comment on lines +142 to +148
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


# Suggestions
- Split the script into two scripts:
- One script to prepare the release branch
- One script to publish to GitHub and crates.io
Comment on lines +150 to +153
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. This is something I'll look into critically. We should also further look into how we can use the workspace feature in cargo release. There's also a PR that includes the --exclude-unchanged arg that should detect crates that don't need to be bumped so we can release with few commands.


## Release branch script
- Remove all git operations other than those used to build Changelogs.
- Remove ordered list of crates and use the directory structure of the repo to determine crates. For this script, dependency order is not important.
- Use existing `crate-changes.sh` script to automatically populate Changelogs
- Increment version numbers
- Update READMEs and dependant `Cargo.toml`.
- The end result should be changes staged to a release branch that includes all version increment work.
Comment on lines +155 to +161
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Thanks Jared. We can start with this.


## Creating PRs and Merging branches

- For this initial work, we should keep the PR and merging processes manual until we are 100% confident that the workflow is accurate and safe.

## Publish script
- This script will need to be aware of crate dependency order, which is difficult. For now we should maybe consider my existing strategy of using a 'release plan' (list of crates to be published)
- This release plan can differ from release to release depending on what needs to be published.
- Switch to main branch (after release PR has been merged)
- For each crate in the release plan
- `cargo publish`
- Wait for crate to appear in crates.io index
- `gh release`