diff --git a/.github/example/prepare-release.event b/.github/example/prepare-release.event new file mode 100644 index 000000000..74f1822d6 --- /dev/null +++ b/.github/example/prepare-release.event @@ -0,0 +1,6 @@ +{ + "action": "workflow_dispatch", + "inputs": { + "versionBump": "minor" + } +} \ No newline at end of file diff --git a/.github/scripts/bump-versions.sh b/.github/scripts/bump-versions.sh new file mode 100755 index 000000000..a30cbd9e5 --- /dev/null +++ b/.github/scripts/bump-versions.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +# $fragment: see possible options https://github.com/christian-draeger/increment-semantic-version/tree/1.2.3?tab=readme-ov-file#version-fragment +if [ "$fragment" = "" ]; then + fragment=$1 +fi + +allowed_crates="protocol oauth core discovery audio metadata playback connect" + +if [ "$fragment" = "patch" ]; then + last_tag=$(git describe --tags --abbrev=0) + awk_crates=$(echo "$allowed_crates" | tr ' ' '|') + diff_crates=$(git diff $last_tag... --stat --name-only \ + | awk '/\.(rs|proto)$/{print}' \ + | awk "/($awk_crates)\//{print}" \ + | cut -d '/' -f 1 \ + | uniq \ + | tr \\n '\ ' \ + | xargs ) + echo "upgrading the following crates: [$diff_crates]" +else + diff_crates=$allowed_crates + echo "upgrading all crates for consistency" +fi + +# append bin so that the version of the binary is also bumped +diff_crates="$diff_crates bin" + +# 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) + +for diff_crate in $diff_crates ; do + if [ "$diff_crate" = "bin" ]; then + toml="./Cargo.toml" + else + toml="./$diff_crate/Cargo.toml" + fi + + 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 + to=$(cat $GITHUB_OUTPUT | cut -d= -f 2) + rm $GITHUB_OUTPUT + + echo "upgrading [librespot-$diff_crate] from [$from] to [$to]" + + # replace version in associated diff_crate toml + sed -i "0,/$from/{s/$from/$to/}" $toml + + if [ "$diff_crate" = "bin" ]; then + continue + fi + + # update workspace dependency in root toml + sed -i "/librespot-$diff_crate/{s/$from/$to/}" ./Cargo.toml + + # update related dependencies in diff_crate + for allowed_crate in $allowed_crates ; do + cat ./$allowed_crate/Cargo.toml | grep librespot-$diff_crate > /dev/null + if [ $? = 0 ]; then + sed -i "/librespot-$diff_crate/{s/$from/$to/}" ./$allowed_crate/Cargo.toml + fi + done +done + +exit 0 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 88b1b8c56..547bd0cc1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,6 @@ name: build - "LICENSE" - "*.sh" - "**/Dockerfile*" - - "publish.sh" - "test.sh" pull_request: paths-ignore: @@ -22,7 +21,6 @@ name: build - "LICENSE" - "*.sh" - "**/Dockerfile*" - - "publish.sh" - "test.sh" schedule: # Run CI every week diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml new file mode 100644 index 000000000..f677a1c4e --- /dev/null +++ b/.github/workflows/prepare-release.yml @@ -0,0 +1,57 @@ +--- +# test with +# act --job prepare-release --eventpath ./.github/example/prepare-release.event +name: prepare release +on: + workflow_dispatch: + inputs: + versionBump: + description: "Version bump for" + required: true + type: choice + options: + - major + - minor + - patch + +jobs: + prepare-release: + name: Prepare release + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + fetch-tags: true + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Bump versions + env: + fragment: ${{ github.event.inputs.versionBump }} + run: ./.github/scripts/bump-versions.sh + + - name: Update Cargo.lock + run: cargo update --workspace + + - name: Get binary version + id: get-version + run: | + VERSION=$(cat ./Cargo.toml | awk "/version/{print; exit}" | cut -d\" -f 2) + echo VERSION=$VERSION >> ${GITHUB_OUTPUT} + + - name: Update Changelog + uses: thomaseizinger/keep-a-changelog-new-release@3.1.0 + with: + tag: v${{ steps.get-version.outputs.VERSION }} + version: ${{ steps.get-version.outputs.VERSION }} + + - name: Commit version prepare + uses: stefanzweifel/git-auto-commit-action@v6 + if: ${{ !env.ACT }} + with: + commit_message: 'Prepare for v${{ steps.get-version.outputs.VERSION }} release' + file_pattern: '*.md *.toml *.lock' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..79576514b --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,34 @@ +name: release.yml +on: + release: + types: + - created + workflow_dispatch: + +jobs: + publish-crates: + name: Publish librespot + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@v2 + + - name: Install dependencies + run: sudo apt-get update && sudo apt-get install -y libasound2-dev + + - name: Verify librespot workspace + run: cargo publish --workspace --dry-run + + - name: Publish librespot workspace + if: ${{ !env.ACT }} + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + run: cargo publish --workspace --no-verify diff --git a/CHANGELOG.md b/CHANGELOG.md index a11d932e4..8a21566bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -158,7 +158,7 @@ will be well worth it. All these changes are likely to introduce new bugs as well as some regressions. We appreciate all your testing and contributions to the repository: -https://github.com/librespot-org/librespot + ### Changed diff --git a/Cargo.toml b/Cargo.toml index 63a5927a7..58cf3b83f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot" -version.workspace = true +version = "0.7.1" rust-version.workspace = true authors.workspace = true license.workspace = true @@ -29,7 +29,6 @@ include = [ ] [workspace.package] -version = "0.7.1" rust-version = "1.85" authors = ["Librespot Org"] license = "MIT" diff --git a/PUBLISHING.md b/PUBLISHING.md index 3859c90a9..d78f767cb 100644 --- a/PUBLISHING.md +++ b/PUBLISHING.md @@ -2,42 +2,41 @@ ## How To -Read through this paragraph in its entirety before running anything. +1. [prepare the release](#prepare-the-release) +2. [create a github-release](#creating-a-github-release) -The Bash script in the root of the project, named `publish.sh` can be used to publish a new version of librespot and its corresponding crates. the command should be used as follows from the project root: `./publish 0.1.0` from the project root, substituting the new version number that you wish to publish. *Note the lack of a v prefix on the version number. This is important, do not add one.* The v prefix is added where appropriate by the script. +### Prepare the release -Make sure that you are are starting from a clean working directory for both `dev` and `master`, completely up to date with remote and all local changes either committed and pushed or stashed. +For preparing the release a manuel workflow should be available that takes care of the common preparation. But +this can also be done manually if so desired. The workflow does: +- upgrade the version according to the targeted release (`major`, `minor`, `patch`) + - `major` and `minor` require all crates to be updated + - `patch` instead only upgrades the crates that had any changes +- updates the changelog according to Keep-A-Changelog convention +- commits and pushes the changes to remote -Note that the script will update the crates and lockfile, so in case you did not do so before, you really should to make sure none of the dependencies introduce some SemVer breaking change. Then commit so you again have a clean working directory. +### Creating a github-release -Also don't forget to update `CHANGELOG.md` with the version number, release date, and at the bottom the comparison links. +After everything is prepared for the new version. A [new release can be created](https://github.com/librespot-org/librespot/releases/new) +from the ui. The tag will not be available as it isn't set by the prepare workflow, so a new tag needs to be created. -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). +The tag and name of the release should be named like `v` where `version` is the version of the binary to be +published. As release notes, copy the entries from the changelog for this release. -Depending on your system the script may fail to publish the main `librespot` crate after having published all the `librespot-xyz` sub-crates. If so then make sure the working directory is committed and pushed (watch `Cargo.toml`) and then run `cargo publish` manually after `publish.sh` finished. +The release should be created as draft, which will trigger the workflow that will publish the changed crates and binary. +The workflow will: +- check if all crates needs to be published or only certain crates +- publish the crates in a specific order while excluding crates that didn't have any changes +- publish the binary -To publish the crates your GitHub account needs to be authorized on `crates.io` by `librespot-org`. First time you should run `cargo login` and follow the on-screen instructions. - -## What the script does - -This is briefly how the script works: - - - Change to branch master, pull latest version, merge development branch. - - Change to working directory. - - Change version number in all files. - - Update crates and lockfile. - - Commit and tag changes. - - Publish crates in given order. - - Push version commit and tags to master. +After the workflow was successful the version can be published. ## Notes -Publishing librespot to crates.io is a slightly convoluted affair due to the various dependencies that each package has on other local packages. The order of publising that has been found to work is as follows: - -`protocol -> core -> audio -> metadata -> playback -> connect -> librespot` - -The `protocol` package needs to be published with `cargo publish --no-verify` due to the build script modifying the source during compile time. - -Publishing can be done using the command `cargo publish` in each of the directories of the respective crate. +Publishing librespot to crates.io is a slightly convoluted affair due to the various dependencies that each package has +on other local packages. The order of publishing that has been found to work is as follows: +> `protocol -> core -> audio -> metadata -> playback -> connect -> librespot` -The script is meant to cover the standard publishing process. There are various improvements that could be made, such as adding options such as the user being able to add a changelog, though this is not the main focus, as the script is intended to be run by a CI. Feel free to improve and extend functionality, keeping in mind that it should always be possible for the script to be run in a non-interactive fashion. +The `protocol` package needs to be published with `cargo publish --no-verify` due to the build script modifying the +source during compile time. Publishing can be done using the command `cargo publish` in each of the directories of the +respective crate. diff --git a/audio/Cargo.toml b/audio/Cargo.toml index 3ff3aac15..b4ea736b5 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-audio" -version.workspace = true +version = "0.7.1" rust-version.workspace = true authors = ["Paul Lietar "] license.workspace = true diff --git a/connect/Cargo.toml b/connect/Cargo.toml index 08d24f66e..e5e6ae1f5 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-connect" -version.workspace = true +version = "0.7.1" rust-version.workspace = true authors = ["Paul Lietar "] license.workspace = true diff --git a/core/Cargo.toml b/core/Cargo.toml index f91a1b387..ff18d7c71 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-core" -version.workspace = true +version = "0.7.1" rust-version.workspace = true authors = ["Paul Lietar "] license.workspace = true diff --git a/discovery/Cargo.toml b/discovery/Cargo.toml index 2f86d5ac0..238ef466a 100644 --- a/discovery/Cargo.toml +++ b/discovery/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-discovery" -version.workspace = true +version = "0.7.1" rust-version.workspace = true authors = ["Paul Lietar "] license.workspace = true diff --git a/metadata/Cargo.toml b/metadata/Cargo.toml index d2d434ee6..8f656cad1 100644 --- a/metadata/Cargo.toml +++ b/metadata/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-metadata" -version.workspace = true +version = "0.7.1" rust-version.workspace = true authors = ["Paul Lietar "] license.workspace = true diff --git a/oauth/Cargo.toml b/oauth/Cargo.toml index 31d58df0e..206ab9af6 100644 --- a/oauth/Cargo.toml +++ b/oauth/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-oauth" -version.workspace = true +version = "0.7.1" rust-version.workspace = true authors = ["Nick Steel "] license.workspace = true diff --git a/playback/Cargo.toml b/playback/Cargo.toml index 2001c680b..7abab1307 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-playback" -version.workspace = true +version = "0.7.1" rust-version.workspace = true authors = ["Sasha Hilton "] license.workspace = true diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index 1d880e4b8..d48c2f1c1 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-protocol" -version.workspace = true +version = "0.7.1" rust-version.workspace = true authors = ["Paul LiƩtar "] license.workspace = true diff --git a/publish.sh b/publish.sh deleted file mode 100755 index 94eedf252..000000000 --- a/publish.sh +++ /dev/null @@ -1,204 +0,0 @@ -#!/bin/bash - -SKIP_MERGE='false' -DRY_RUN='false' - -WORKINGDIR="$( cd "$(dirname "$0")" ; pwd -P )" -cd $WORKINGDIR - -# Order: dependencies first (so "librespot" using everything before it goes last) -crates=( "protocol" "oauth" "core" "discovery" "audio" "metadata" "playback" "connect" "librespot" ) - -function replace_in_file() { - OS=`uname` - shopt -s nocasematch - case "$OS" in - darwin) - # for macOS - sed -i '' -e "$1" "$2" - ;; - *) - # for Linux and Windows - sed -i'' -e "$1" "$2" - ;; - esac -} - -function switchBranch { - if [ "$SKIP_MERGE" = 'false' ] ; then - # You are expected to have committed/stashed your changes before running this. - echo "Switching to master branch and merging development." - git checkout master - git pull - if [ "$DRY_RUN" = 'true' ] ; then - git merge --no-commit --no-ff dev - else - git merge dev - fi - fi -} - -function updateVersion { - for CRATE in "${crates[@]}" - do - if [ "$CRATE" = "librespot" ] - then - CRATE_DIR='' - else - CRATE_DIR=$CRATE - fi - crate_path="$WORKINGDIR/$CRATE_DIR/Cargo.toml" - crate_path=${crate_path//\/\///} - $(replace_in_file "s/^version =.*/version = \"$1\"/g" "$crate_path") - echo "Path is $crate_path" - if [ "$CRATE" = "librespot" ] - then - echo "Updating lockfile" - if [ "$DRY_RUN" = 'true' ] ; then - cargo update --dry-run - git add . && git commit --dry-run -a -m "Update Cargo.lock" - else - cargo update - git add . && git commit -a -m "Update Cargo.lock" - fi - fi - done -} - -function commitAndTag { - if [ "$DRY_RUN" = 'true' ] ; then - # Skip tagging on dry run. - git commit --dry-run -a -m "Update version numbers to $1" - else - git commit -a -m "Update version numbers to $1" - git tag "v$1" -a -m "Update to version $1" - fi -} - -function get_crate_name { - awk -v FS="name = " 'NF>1{print $2; exit}' Cargo.toml -} - -function publishCrates { - for CRATE in "${crates[@]}" - do - if [ "$CRATE" = "librespot" ] - then - CRATE='' - fi - - crate_path="$WORKINGDIR/$CRATE" - crate_path=${crate_path//\/\///} - cd $crate_path - # Also need to update Cargo.lock in root directory - crate_name=`echo $( awk -v FS="name = " 'NF>1{print $2; exit}' Cargo.toml )` - echo "Publishing $crate_name to crates.io" - if [ "$CRATE" == "protocol" ] - then - # Protocol crate needs --no-verify option due to build.rs modification. - if [ "$DRY_RUN" = 'true' ] ; then - cargo publish --no-verify --dry-run - else - cargo publish --no-verify - fi - else - if [ "$DRY_RUN" = 'true' ] ; then - cargo publish --dry-run - else - cargo publish - fi - fi - echo "Successfully published $crate_name to crates.io" - done -} - -function updateRepo { - cd $WORKINGDIR - if [ "$DRY_RUN" = 'true' ] ; then - echo "Pushing to master branch of repo. [DRY RUN]" - git push --dry-run origin master - echo "Pushing v$1 tag to master branch of repo. [DRY RUN]" - git push --dry-run origin v$1 - - # Cancels any merges in progress - git merge --abort - - git checkout dev - git merge --no-commit --no-ff master - - # Cancels above merge - git merge --abort - - git push --dry-run - else - echo "Pushing to master branch of repo." - git push origin master - echo "Pushing v$1 tag to master branch of repo." - git push origin v$1 - # Update the dev repo with latest version commit - git checkout dev - git merge master - git push - fi -} - -function rebaseDev { - git checkout dev - git merge master - git push -} - -function run { - switchBranch - updateVersion $1 - commitAndTag $1 - publishCrates - updateRepo $1 - rebaseDev - echo "Successfully published v$1 to crates.io and uploaded changes to repo." -} - -#Set Script Name variable -SCRIPT=`basename ${BASH_SOURCE[0]}` - -print_usage () { - local l_MSG=$1 - if [ ! -z "${l_MSG}" ]; then - echo "Usage Error: $l_MSG" - fi - echo "Usage: $SCRIPT " - echo " where specifies the version number in semver format, eg. 1.0.1" - echo "Recognized optional command line arguments" - echo "--dry-run -- Test the script before making live changes" - echo "--skip-merge -- Skip merging dev into master before publishing" - exit 1 -} - -### check number of command line arguments -NUMARGS=$# -if [ $NUMARGS -eq 0 ]; then - print_usage 'No command line arguments specified' -fi - -while test $# -gt 0; do - case "$1" in - -h|--help) - print_usage - exit 0 - ;; - --dry-run) - DRY_RUN='true' - shift - ;; - --skip-merge) - SKIP_MERGE='true' - shift - ;; - *) - break - ;; - esac -done - -# First argument is new version number. -run $1