Skip to content

Conversation

photovoltex
Copy link
Member

@photovoltex photovoltex commented Aug 27, 2025

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 (only created because we want to create a draft and only publish when the workflow is done).

Maybe we could also use this already for 0.7.1, then we would see how only some crates are updated as only playback, connect and core changed so far.

Disclaimer:

  • what is missing for this to work:
    • we need to at a secret to the repository for crates.io access
  • what I couldn't test so far:
    • commit and pushing in the preparation workflow
    • the publish itself in the release workflow, but as dry-run it seems to work well

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.
Copy link
Member Author

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?

Copy link
Member

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.tomls: 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 full cargo 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.

Copy link
Member Author

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.

Copy link
Contributor

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.tomls: 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 full cargo update before.

Is this just for major and minor releases ? Patch/fix releases ideally shouldn't bump the deps, right?

Copy link
Member Author

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.

Copy link
Contributor

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.

Copy link
Member Author

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.

Copy link
Contributor

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.

Copy link
Member

Choose a reason for hiding this comment

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

Fully agreed.

@photovoltex photovoltex requested a review from roderickvd August 29, 2025 21:56
for crate in $CRATES ; do
cat $TOML | grep librespot-$crate > /dev/null
if [ $? = 0 ]; then
sed -i "/librespot-$CRATE/{s/$FROM/$TO/}" $TOML
Copy link
Member

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

Copy link
Member Author

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"
Copy link
Member

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 }}
Copy link
Member

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?

Copy link
Member Author

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?

Copy link
Member

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?

Copy link
Member Author

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.

Copy link
Member Author

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]+)$"
Copy link
Member

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 😄

Copy link
Member Author

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.

Copy link
Member

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}' \
Copy link
Member

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.

Copy link
Member Author

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?

Copy link
Member

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

Copy link
Member Author

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}" \
Copy link
Member

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)

Copy link
Member Author

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?

Copy link
Member Author

@photovoltex photovoltex Aug 30, 2025

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

Copy link
Member

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".

@roderickvd
Copy link
Member

Ooohh, from Rust 1.90.0 release:

Cargo adds native support for workspace publishing

cargo 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.

@photovoltex
Copy link
Member Author

I'm currently adjusting the release workflow to use that new info. How does that interact with crates that generate code and need --no-verify as flag, like protocol? Does that mean you have to use --no-verify for the entire workspace then?

@Copilot Copilot AI review requested due to automatic review settings September 24, 2025 21:39
Copy link
Contributor

@Copilot Copilot AI left a 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)
Copy link
Preview

Copilot AI Sep 24, 2025

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.

Suggested change
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
Copy link
Preview

Copilot AI Sep 24, 2025

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
Copy link
Preview

Copilot AI Sep 24, 2025

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.

Suggested change
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
Copy link
Preview

Copilot AI Sep 24, 2025

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.

Suggested change
sed -i "0,/$from/{s/$from/$to/}" $toml
sed -i "s/^version = \"$from\"/version = \"$to\"/" $toml

Copilot uses AI. Check for mistakes.

@photovoltex
Copy link
Member Author

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

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

Successfully merging this pull request may close these issues.

3 participants