diff --git a/.github/workflows/release-commit.yml b/.github/workflows/release-commit.yml new file mode 100644 index 0000000..bc8cd04 --- /dev/null +++ b/.github/workflows/release-commit.yml @@ -0,0 +1,54 @@ +# Create a new commit +# This action bumps the Cargo.toml version and updates related files. +# Updates will affect the following files: +# - ./Cargo.toml +# - ./Cargo.lock +# - ./THIRD-PARTY-LICENSES.md +# - ./CHANGELOG.md +name: "Release Commit" +on: + workflow_dispatch: + inputs: + bump_level: + description: "What type of release is this?" + required: true + type: choice + options: + - minor + - patch +permissions: + contents: write + +jobs: + setup-environment: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Add git tag to release + run: ./scripts/create_release_changes ${{ github.event.inputs.text_input }} + + - name: Get new cargo version + id: cargo_version + run: | + VERSION=$(cargo read-manifest | jq -r ".version") + echo "value=v$VERSION" >> $GITHUB_OUTPUT + + - name: Ensure this release doesn't already exist + run: | + if git log --grep="Release ${{ steps.cargo_version.outputs.value }}" --quiet; then + echo "Release commit already exists: \"Release ${{ steps.cargo_version.outputs.value}}\"" + exit 1 + fi + + - name: Commit the changes + uses: stefanzweifel/git-auto-commit-action@ac8823709a85c7ce090849ac3e5fe24d006f6e18 # v5.0.1 + with: + commit_message: "Release ${{ steps.cargo_version.outputs.value }}" + branch: ${{ github.head_ref }} + commit_user_name: tinted-theming-bot + commit_user_email: tintedtheming@proton.me + commit_author: tinted-theming-bot diff --git a/RELEASE.md b/RELEASE.md index f56cd88..d44f29f 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,32 +1,19 @@ # Release process -1. Create a release commit. This includes specific updated files: - - 1. Cargo.toml (Bump the version using [semver] standards) - 1. Cargo.lock (This is usually updated automatically with the `cargo` - CLI tool) - 1. Make sure the changes for the new release exist under - `CHANGELOG.md`. This should already exist since changes done in - GitHub Pull Requests should include updates to the `CHANGELOG.md`. - If this doesn't exist, the release will fail. - 1. Change `CHANGELOG.md` `## Unreleased` to `## [x.x.x] - YYYY-MM-DD` - where `x.x.x` is the new Tinty version specified in the - `Cargo.toml` file and the link to `[x.x.x]` at the bottom of the - `CHANGELOG.md` file and compare it with the previously released - version, eg: - - ```md - [0.22.0]: https://github.com/tinted-theming/tinty/compare/v0.21.1...v0.22.0 - ``` - - 1. Run `cargo about generate about.hbs > LICENSES-THIRD-PARTY.md` to - update the third party licenses. (`cargo install cargo-about` if - you don't have it installed) - 1. Create a commit with the 3 changed files titled `Release x.x.x` - where `x.x.x` is the new Tinty version specified in the - `Cargo.toml` file - -1. Push the commit or create a Pull Request and merge +1. Make sure `## Unreleased` section exists in [CHANGELOG.md] +1. Run [Release Commit GitHub action]. Select `minor` or `patch` as a + dispatch value option. This follows the [semver] pattern. + + - `minor` if changes include new features or breaking changes + - `patch` if the change only contains bug fixes + + This action does the following: + + 1. Bumps `Cargo.toml` version by `minor` or `patch` + 1. Updates `Cargo.lock` with the new version + 1. Updates [CHANGELOG.md] `## Unreleased` section to the new version + 1. Updates [LICENSE-THIRD-PARTY.md] + 1. Once the CI tests have passed, run the [Release GitHub action]. This will automatically do the following: @@ -35,11 +22,15 @@ 1. Create a release under [GitHub releases] with the changes mentioned in `CHANGELOG` 1. Generate the various binaries and add it to the GitHub release + 1. Run the [homebrew-tinted] [Update CLI tool GitHub action] and specify `tinty` as the action input value. This will update the version for [Homebrew] [semver]: https://semver.org/ +[CHANGELOG.md]: ./CHANGELOG.md +[LICENSE-THIRD-PARTY.md]: ./LICENSE-THIRD-PARTY.md +[Release Commit GitHub action]: https://github.com/tinted-theming/tinty/actions/workflows/release-commit.yml [Release GitHub action]: https://github.com/tinted-theming/tinty/actions/workflows/release.yml [GitHub releases]: https://github.com/tinted-theming/tinty/releases [homebrew-tinted]: https://github.com/tinted-theming/homebrew-tinted diff --git a/scripts/create_release_changes b/scripts/create_release_changes new file mode 100755 index 0000000..e05f899 --- /dev/null +++ b/scripts/create_release_changes @@ -0,0 +1,119 @@ +#!/usr/bin/env bash + +main() { + local level="$1" # Supported: [major|minor|patch] + local old_version=$(get_cargo_version) + + # Ensure things are as expected before doing anything + setup + + bump_cargo_version "$level" + + local new_version="$(get_cargo_version)" + version_changelog "$old_version" "$new_version" + + update_third_party_licenses + check_for_unauthorized_changes +} + +setup() { + # Ensure there are no changes in the repository + if [[ -n $(git status --porcelain) ]]; then + echo "Uncommitted changes or untracked files already exist in the repository." + exit 1 + fi +} + +# Extract the version from Cargo.toml +get_cargo_version() { + local cargo_toml="./Cargo.toml" + local version=$(grep -m 1 '^version =' "$cargo_toml" | sed -E 's/version = "(.*)"/\1/') + + if [[ -z "$version" ]]; then + echo "Version not found in Cargo.toml" + exit 1 + fi + + echo "$version" +} + +# Bump version in Cargo.toml +bump_cargo_version() { + local level="$1" + local version=$(get_cargo_version "$level") + local cargo_toml="./Cargo.toml" + + # Split version into major, minor, patch + IFS='.' read -r major minor patch <<< "$version" + echo "Current version: $version" + + # Increment based on major, minor or patch + if [[ "$level" == "major" ]]; then + major=$((major + 1)) + minor=0 + patch=0 + elif [[ "$level" == "minor" ]]; then + minor=$((minor + 1)) + patch=0 + elif [[ "$level" == "patch" ]]; then + patch=$((patch + 1)) + else + echo "Usage: $0 [major|minor|patch]" + exit 1 + fi + + local updated_version="$major.$minor.$patch" + sed -i -E "s/^version = \"$version\"$/version = \"$updated_version\"/" "$cargo_toml" + + echo "Updated Cargo.toml to version $updated_version" +} + +# Add version and date to "Unreleased" section in changelog +version_changelog() { + local old_version="$1" + local new_version="$2" + local changelog_file="./CHANGELOG.md" + + if [[ ! $(grep '^## Unreleased' "$changelog_file") ]]; then + echo "Warning: CHANGELOG.md does not have an 'Unreleased' section" + exit 1 + fi + + local current_date=$(TZ=UTC date +"%Y-%m-%d") + + sed -i -E "s/## Unreleased/## \[$new_version\] - $current_date/" "$changelog_file" + sed -i "/^\[$old_version\]: /i \[$new_version\]: https://github.com/tinted-theming/tinty/compare/v$old_version...v$new_version" "$changelog_file" + + echo "Updated CHANGELOG.md with $new_version" +} + +# Update third-party licenses with `cargo about` +update_third_party_licenses() { + local license_file="./LICENSES-THIRD-PARTY.md" + + cargo deny check + cargo about generate about.hbs > "$license_file" + + echo "Updated third-party licenses" +} + +# Exit if disallowed files contain changes +check_for_unauthorized_changes() { + local allowed_files=("Cargo.toml" "Cargo.lock" "LICENSES-THIRD-PARTY.md" "CHANGELOG.md") + local changed_files=$(git status --porcelain | awk '{print $2}') + local unauthorized_changes=0 + + for file in $changed_files; do + if [[ ! " ${allowed_files[*]} " =~ " ${file} " ]]; then + echo "Unauthorized change detected: $file" + unauthorized_changes=1 + fi + done + + if [[ $unauthorized_changes -eq 1 ]]; then + echo "Error: Only allow-listed files may change: ${allowed_files[*]}." + exit 1 + fi +} + +main "$@"