From 9ada4423e4684f1a141d5fb137f9cc66218c1ac3 Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Wed, 31 Jul 2024 14:33:14 +0300 Subject: [PATCH] ci: Fix release flow --- .github/workflows/main.yml | 18 ++--- RELEASING.md | 39 +++++++++++ release.sh | 131 +++++++++++++++++++++++++++++++++++++ scripts/get-module-name.sh | 23 +++++++ 4 files changed, 200 insertions(+), 11 deletions(-) create mode 100644 RELEASING.md create mode 100755 release.sh create mode 100755 scripts/get-module-name.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4cec74a..02ae15e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,11 +3,9 @@ name: CI on: push: branches: [main] - # Release tag format is [module-name]-[namespace-name]-v[version]-[sub-version] - # For example: fragment-ktx-v1.3.5-0, compose-gears-v.1.1.1-1 - tags: - - '*-ktx-v*-[0-9]+' - - '*-gears-v*-[0-9]+' + # Release tag format is [library-name]-v[version] + # Examples: fragment-ktx-v1.3.5-0, gears-compose-v1.1.1, resultflow-v0.1.0 + tags: ['*-v*'] pull_request: branches: [main] @@ -36,7 +34,7 @@ jobs: run: ./gradlew detektAll detektReleaseAll publish: - name: Publish gears + name: Publish needs: check runs-on: ubuntu-latest if: ${{ startsWith(github.ref, 'refs/tags/') }} @@ -51,20 +49,18 @@ jobs: distribution: 'temurin' java-version: 17 - - name: Get namespace and module name from tag + - name: Get module name from tag id: parse-tag run: | tag=${GITHUB_REF#refs/tags/} - module=$(echo "${tag%-*-v*}") - namespace=$(echo "${tag/-v*}" | rev | cut -d '-' -f 1 | rev) + module=$(./scripts/get-module-name.sh "$tag") echo "module=$module" >> "$GITHUB_OUTPUT" - echo "namespace=$namespace" >> "$GITHUB_OUTPUT" - name: Setup Gradle uses: gradle/actions/setup-gradle@v3 - name: Run Publish - run: ./gradlew :${{ steps.parse-tag.outputs.namespace }}:${{ steps.parse-tag.outputs.module }}:publish + run: ./gradlew ${{ steps.parse-tag.outputs.module }}:publish env: ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_USERNAME }} ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_PASSWORD }} diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..de7e216 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,39 @@ +# Releasing + +1. Run the script `release.sh` with release name in format `[library]-v[version]`: + ```bash + ./release.sh gears-compose-v1.0.0 + ```` + +2. The script will ask you if you want to push the release branch and create a release tag. + +3. Ensure `CHANGELOG.md` looks good and is ready to be published. + Make the necessary edits. + +4. Type "yes" to the console if everything is okay. + +5. Click the link printed in the console to create a Pull Request for release branch. + +6. Merge the Pull Request as soon as the "Check" workflow succeeds. + +Release tag push triggers a GitHub Actions workflow, which publishes the release artifacts to Maven Central and creates a GitHub release. + +## Manual release preparation + +To prepare the release manually, follow the steps the script does: + +1. Ensure the repository is up to date, and the main branch is checked out. + +2. Create the release branch with the name `release/[library]-v[version]` + +3. Update the version in `gradle.properties`, `build.gradle.kts` and `README.md` ("Usage" section). + +4. Update the `CHANGELOG.md`: + 1. Replace `Unreleased` section with the release version + 2. Add a link to the diff between the previous and the new version (if possible) + 3. Add a new empty `Unreleased` section on the top + +5. Commit the changes, create a tag on the commit, and push it to the remote repository. + The tag should follow the format `[library]-v[version]`. + +6. Create a Pull Request for the release branch and merge it. diff --git a/release.sh b/release.sh new file mode 100755 index 0000000..c6e1e0f --- /dev/null +++ b/release.sh @@ -0,0 +1,131 @@ +#!/usr/bin/env bash +# +# Prepares the specified library for release. Creates a release branch from the 'main'. +# +# Usage: ./release.sh [release-name] +# Where `release-name` is: [library-name]-v[version] +# +# Example: ./release.sh gears-compose-v1.0.0 +# +# Original release script: https://github.com/RedMadRobot/android-library-template/blob/main/release.sh + +set -euo pipefail + +# The script could be run from any directory. +cd "$(dirname "$0")" + +# Handle release input parameter +release=${1:?Please specify the release to be released as a parameter} +module=$(./scripts/get-module-name.sh "$release") +module_path=${module#:} # :gears:gears-compose -> gears:gears-compose +module_path=${module_path//://} # gears:gears-compose -> gears/gears-compose +library=${release%-v*} # gears-compose-v1.0.0 -> gears-compose + +# Configure the script +properties="$module_path/gradle.properties" +changelog="$module_path/CHANGELOG.md" +readme="$module_path/README.md" +build_script="$module_path/build.gradle.kts" +files_to_update_version=("$properties" "$build_script" "$readme") +github_repository_url="https://github.com/RedMadRobot/gears-android" + +#region Utils +function error() { + echo "❌ $1" + return 1 +} + +function get_current_version() { + local version="" + if [[ -f $properties ]]; then + version=$(grep "^version=" "$properties") + fi + + if [[ -z $version && -f $build_script ]]; then + version=$(grep "^version = \"" "$build_script") + fi + + if [[ -z $version ]]; then + error "Can't find current version. Checked locations: $properties, $build_script" + fi + + echo "$version" | cut -d'=' -f2 | tr -d ' "' +} + +function replace() { + local file=$3 + + # Escape linebreaks + local replacement=${2//$'\n'/\\\n} + # Portable in-place edit. + # See: https://stackoverflow.com/a/4247319 + sed -i".bak" -E "s~$1~$replacement~g" "$file" + rm "$file.bak" +} + +function diff_link() { + echo -n "$github_repository_url/compare/${1}...${2}" +} +#endregion + +# Check if the module exists +[[ -d $module_path ]] || error "Module '$module' not found on path '$module_path'." + +# 0. Fetch remote changes +echo "️⏳ Creating release branch..." +release_branch="release/$release" +git checkout --quiet -b "$release_branch" +git pull --quiet --rebase origin main +echo "✅ Branch '$release_branch' created" +echo + +# 1. Calculate module and version values for later +last_version=$(get_current_version) +version=${release##*-v} # library-v1.0.0 -> 1.0.0 +if [[ "$last_version" == "$version" ]]; then + echo "🤔 Version $version is already set." + exit 0 +fi +echo "🚀 [$module] Update $last_version → $version" +echo + +# 2. Update version everywhere +for file in "${files_to_update_version[@]}" ; do + if [[ -f $file ]]; then + replace "$last_version" "$version" "$file" + echo "✅ Updated version in $file" + fi +done + +# 3. Update header in CHANGELOG.md +date=$(date -u +%Y-%m-%d) +header_replacement=\ +"## Unreleased + +- *No changes* + +## $version ($date)" +replace "^## Unreleased.*" "$header_replacement" "$changelog" +echo "✅ Updated CHANGELOG.md header" + +# 4. Ask if the changes should be pushed to remote branch +echo +echo "Do you want to commit the changes and push the release branch and tag?" +echo "The release tag push triggers a release workflow on CI." +read -p " Enter 'yes' to continue: " -r input +if [[ "$input" != "yes" ]]; then + echo "👌 SKIPPED." + exit 0 +fi + + + +# 5. Push changes, trigger release on CI, and give a link to open PR +echo +echo "⏳ Pushing the changes to the remote repository..." +git add "$readme" "$changelog" "$properties" "$build_script" +git commit --quiet --message "$library: $version" +git tag "$release" +git push --quiet origin HEAD "$release" +echo "🎉 DONE." +echo "Create a Pull Request: $(diff_link main "$release_branch")" diff --git a/scripts/get-module-name.sh b/scripts/get-module-name.sh new file mode 100755 index 0000000..41108a2 --- /dev/null +++ b/scripts/get-module-name.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# +# Retrieves Gradle module name from the given version tag. +# Examples: +# gears-compose-v1.0.0 -> :gears:gears-compose +# core-ktx-v1.0.0-1 -> :ktx:core-ktx +# resultflow-v1.0.0 -> :resultflow +# + +set -eu + +tag=$1 +library=${tag%-v*} # Remove version suffix + +# Handle prefix for inner modules +prefix=":" +if [[ $library == *-ktx ]]; then + prefix=":ktx:" +elif [[ $library == gears-* ]]; then + prefix=":gears:" +fi + +echo "$prefix$library"