-
Notifications
You must be signed in to change notification settings - Fork 748
CI: Add a release preparation and release workflow #1559
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
base: dev
Are you sure you want to change the base?
Conversation
PUBLISHING.md
Outdated
The tag should be named like `v<version>` where `version` is the version of the binary. | ||
|
||
You will want to perform a dry run first: `./publish --dry-run 0.1.0`. Please make note of any errors or warnings. In particular, you may need to explicitly inform Git which remote you want to track for the `master` branch like so: `git --track origin/master` (or whatever you have called the `librespot-org` remote `master` branch). | ||
> insert convention what the release title and release notes should be and what checkboxes to check etc. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@roderickvd You did the release most of the time, anything that would be worth mentioning here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's what I can think of now:
-
We follow Semantic Versioning MAJOR.MINOR.PATCH like v0.8.2. As librespot is pre-1.0, every breaking change bumps the minor version.
-
The CHANGELOG.md needs to be updated before release: version and date set, and (at the bottom) one link added (of the new version) and one link updated (unreleased between the new release and HEAD).
-
Versions are to be updated in all
Cargo.toml
s: both the package version (in case it doesn't inherit) as well as the dependencies on the other workspace members. -
Cargo.lock
is to be regenerated, so it takes the latest librespot version number. This may trigger updating the dependencies too - it's good to test that or do a fullcargo update
before. -
Wait for CI to pass.
-
Release is to be tagged and a release created on GitHub. Tag name and release name should simply be the version string (v0.8.2) without the parentheses. As release notes, copy the entries from the changelog for this release.
-
cargo publish
is to be ran in the appropriate order (deepest node in the dependency tree first, complete librespot last). -
After publishing, it's helpful to update the changelog with a new "Unreleased" section and "Added / Fixed / Removed / etc." sub-sections.
Not listing any of the "dev -> master" stuff as I believe we want to get rid of that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think most of that I have written down in PUBLISH.md
already. Here explicitly I was asking for the github-release part. But you also answered that, so I will insert the part here then.
For the other steps:
Step 1-4 are taken care of from the prepare-release
workflow that can be triggered manually beforehand.
Step 7 is handled automatically via the release
workflow.
Step 8 I think is partly done by Step 2 from the prepare workflow. I would actually keep the section empty and point to "keep-a-changelog"'s best practice for new contributes. By that only necessary sections are added.
The whole "dev->master" workflow I have completely removed as discussed beforehand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's what I can think of now:
We follow Semantic Versioning MAJOR.MINOR.PATCH like v0.8.2. As librespot is pre-1.0, every breaking change bumps the minor version.
The CHANGELOG.md needs to be updated before release: version and date set, and (at the bottom) one link added (of the new version) and one link updated (unreleased between the new release and HEAD).
Versions are to be updated in all
Cargo.toml
s: both the package version (in case it doesn't inherit) as well as the dependencies on the other workspace members.
Cargo.lock
is to be regenerated, so it takes the latest librespot version number. This may trigger updating the dependencies too - it's good to test that or do a fullcargo update
before.
Is this just for major and minor releases ? Patch/fix releases ideally shouldn't bump the deps, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the prepare workflow currently calls cargo update --workspace
which only updates the workspace dependencies and no external dependencies which works quite well for our use case. I think updating dependencies should be done manually or by something like a bot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my perspective, for patch releases, minimal changes except the fixes we want would be nice, they are supposed to be drop-in replacement updates. So I'd advocate for no cargo update in that case. New versions of deps means new bugs! Maybe that's at odds with Rust development best practices, I don't have experience.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A single run of cargo update --workspace
is necessary. Otherwise you will not update the version of our librespot crates in the lock file and then the new release will not use these.
You can try this locally but from testing supplying --workspace
only updates the versions of our librespot crates, so no dependency is bumped. I would also go that far and say bumping versions should never be done automatically before a release (regardless of major, minor or patch) in itself to ensure a stable and tested release.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sorry, I misunderstood. Only our crates is great. And yes, absolutely no automatic external dep version bumps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fully agreed.
.github/scripts/bump-versions.sh
Outdated
for crate in $CRATES ; do | ||
cat $TOML | grep librespot-$crate > /dev/null | ||
if [ $? = 0 ]; then | ||
sed -i "/librespot-$CRATE/{s/$FROM/$TO/}" $TOML |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change variable into lower case ⬇️
sed -i "/librespot-$crate/{s/$FROM/$TO/}" $TOML
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can do, will be interesting as $crate
and $CRATE
are two different variables, but will mean I have to rename one.
@@ -0,0 +1,49 @@ | |||
CRATES="protocol oauth core discovery audio metadata playback connect" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could use a #!/usr/bin/env bash
|
||
- name: Commit version prepare | ||
uses: stefanzweifel/git-auto-commit-action@v6 | ||
if: ${{ !env.ACT }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we check more generally for development environments besides ACT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And how would that look like? Or what different development environment do you have in mind?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah don't know how we can make that work with GitHub actions? Not an expert.
But if we would have something like:
if: ${{ env.PRODUCTION }}
then that could be more robust.
Can we set that environment variable somehow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah good point restricting it from the other side. I will take a look if there is something github provides.
Even tho I think this will break the intention of not running this step locally when using act, but I will report about that when I looked into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I tried to find something similar that is supported by github out of the box, but I couldn't find anything. So only disabling it when using act seems good enough from my perspective.
|
||
BIN_VERSION=$(cat ./Cargo.toml | awk "/version/{print; exit}" | cut -d\" -f 2) | ||
|
||
SIMPLE_VERSION_REGEX="^v?([0-9]+)\.([0-9]+)\.([0-9]+)$" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one should match special versions (e.g., v1.0.0-beta.1, v1.0.0-rc.1) and those with build metadata(e.g., v1.0.0+20130313144700), and not match invalid versions like v999999999999999999.0.0:
SEMVER_REGEX="^v?([0-9]+)\.([0-9]+)\.([0-9]+)(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$"
Please verify it though 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we intend to use pre-release versions? I wanted to keep the regex as simple as possible as otherwise the whole logic around what version jump we made would explode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We haven't yet. So OK by not supporting it for now.
# if we go through here, we build a patch version and only want to update the crates that have changed | ||
AWK_CRATES=$(echo "$CRATES" | tr ' ' '|') | ||
DIFF_CRATES=$(git diff $LAST_TAG... --stat --name-only \ | ||
| awk '/(rs|proto)$/{print}' \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
awk '/\.(rs|proto)$/{print}' \
Won't match files like something.cars or myproto.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well that's the idea, we only want to match against files that would change the code, which are currently rust (.rs) and proto (.proto) files. Unless there are some other files I forgot to include?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant to say: the current one does match you_dont_need_this.cars
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OH, I also mistook your quote as my code^^; Yeah can fix that. Good find
AWK_CRATES=$(echo "$CRATES" | tr ' ' '|') | ||
DIFF_CRATES=$(git diff $LAST_TAG... --stat --name-only \ | ||
| awk '/(rs|proto)$/{print}' \ | ||
| awk "/($AWK_CRATES)/{print}" \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
awk "/^($AWK_CRATES)\//{print}" \
Won't match partial directory names (e.g., if you have metadata-old)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also see that as a intended behavior unless I did miss something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which means I also didn't look close enough here. Will adjust that then
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here I may have been too quick though 😄 as we do want "librespot-metadata".
Ooohh, from Rust 1.90.0 release: Cargo adds native support for workspace publishingcargo publish --workspace is now supported, automatically publishing all of the crates in a workspace in the right order (following any dependencies between them). This has long been possible with external tooling or manual ordering of individual publishes, but this brings the functionality into Cargo itself. Native integration allows Cargo's publish verification to run a build across the full set of to-be-published crates as if they were published, including during dry-runs. Note that publishes are still not atomic -- network errors or server-side failures can still lead to a partially published workspace. |
I'm currently adjusting the release workflow to use that new info. How does that interact with crates that generate code and need |
# Conflicts: # CHANGELOG.md # Cargo.toml
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR replaces the existing manual shell script publishing workflow with an automated GitHub Actions-based release process. The new system separates release preparation from the actual publishing, providing better control and automation.
Key changes:
- Removes the old
publish.sh
script and replaces it with GitHub Actions workflows - Transitions from workspace-based versioning to individual crate versioning for 0.7.1
- Introduces a two-step release process: preparation via manual workflow, then publishing via release creation
Reviewed Changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.
Show a summary per file
File | Description |
---|---|
publish.sh | Removes the legacy bash publishing script |
*/Cargo.toml | Updates all crates to use explicit version "0.7.1" instead of workspace version |
PUBLISHING.md | Updates documentation to describe the new GitHub Actions-based release workflow |
.github/workflows/release.yml | Adds automated workflow for publishing crates when a GitHub release is created |
.github/workflows/prepare-release.yml | Adds manual workflow for preparing releases with version bumping and changelog updates |
.github/workflows/build.yml | Removes publish.sh from ignored paths since it no longer exists |
.github/scripts/bump-versions.sh | Adds script for intelligent version bumping based on changed crates |
.github/example/prepare-release.event | Adds example event file for testing the prepare-release workflow |
CHANGELOG.md | Minor formatting fix to use angle bracket URL format |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
# required by script as it's usually a github action | ||
export GITHUB_OUTPUT="version.txt" | ||
# https://github.com/christian-draeger/increment-semantic-version/tree/1.2.3 | ||
increment_semver=$(curl https://raw.githubusercontent.com/christian-draeger/increment-semantic-version/refs/tags/1.2.3/entrypoint.sh) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Downloading and executing arbitrary scripts from the internet without verification poses a security risk. Consider vendoring this script or using a verified GitHub Action instead.
increment_semver=$(curl https://raw.githubusercontent.com/christian-draeger/increment-semantic-version/refs/tags/1.2.3/entrypoint.sh) | |
increment_semver=$(cat .github/scripts/increment-semver-entrypoint.sh) |
Copilot uses AI. Check for mistakes.
from="$(cat $toml | awk "/version/{print; exit}" | cut -d\" -f 2)" | ||
|
||
# execute script inline, extract result and remove output file | ||
echo "$increment_semver" | bash /dev/stdin $from $fragment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Executing downloaded script content through bash poses a security risk. The script content should be verified or the functionality should be implemented locally.
Copilot uses AI. Check for mistakes.
- name: Checkout code | ||
uses: actions/checkout@v5 | ||
with: | ||
fetch-tags: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter should be fetch-depth: 0
to fetch all history including tags. The fetch-tags
parameter doesn't exist in actions/checkout.
fetch-tags: true | |
fetch-depth: 0 |
Copilot uses AI. Check for mistakes.
echo "upgrading [librespot-$diff_crate] from [$from] to [$to]" | ||
|
||
# replace version in associated diff_crate toml | ||
sed -i "0,/$from/{s/$from/$to/}" $toml |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sed command may incorrectly replace version numbers that appear elsewhere in the file. It should be more specific to target only the version field, e.g., sed -i \"s/^version = \\\"$from\\\"/version = \\\"$to\\\"/\" $toml
.
sed -i "0,/$from/{s/$from/$to/}" $toml | |
sed -i "s/^version = \"$from\"/version = \"$to\"/" $toml |
Copilot uses AI. Check for mistakes.
I tested the workspace publishing with a dry-run for a patch version and that seemed to work quite well. So I adjusted the release workflow to use that, as it reduces a lot of unnecessary complexity |
I think this is in a reviewable state now, where we can discuss over the details.
The idea behind the release flow is described in
PUBLISHING.md
. But broken down, there is a manual workflow that takes care of the manual preparation steps and a automatic workflow that is triggered when a github release is created (onlycreated
because we want to create a draft and only publish when the workflow is done).Disclaimer: