docs: add 2.2.0 changelog entry #81
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CD Pipeline | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ["v*"] | |
| paths-ignore: | |
| - "docs/**" | |
| - "*.md" | |
| - ".github/**" | |
| - ".kiro/**" | |
| workflow_dispatch: | |
| inputs: | |
| version_name: | |
| description: "Version name for the release" | |
| required: false | |
| default: "manual-build" | |
| permissions: | |
| contents: write | |
| packages: write | |
| jobs: | |
| build-and-deploy: | |
| name: Build and Deploy | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Extract version and determine deployment | |
| id: version | |
| env: | |
| GITHUB_REF: ${{ github.ref }} | |
| GITHUB_REF_NAME: ${{ github.ref_name }} | |
| GITHUB_RUN_NUMBER: ${{ github.run_number }} | |
| VERSION_NAME_INPUT: ${{ github.event.inputs.version_name }} | |
| run: | | |
| if [[ "$GITHUB_REF" == refs/tags/v* ]]; then | |
| VERSION_NAME="$GITHUB_REF_NAME" | |
| VERSION_NAME="${VERSION_NAME#v}" # Remove 'v' prefix | |
| DEPLOY_TARGET="production" | |
| IS_TAG_BUILD="true" | |
| echo "Tag build detected: $VERSION_NAME -> production release" | |
| elif [[ "$GITHUB_REF" == refs/heads/main ]]; then | |
| VERSION_NAME="main-$GITHUB_RUN_NUMBER" | |
| DEPLOY_TARGET="beta" | |
| IS_TAG_BUILD="false" | |
| echo "Main branch build: $VERSION_NAME -> open testing" | |
| else | |
| if [[ -z "$VERSION_NAME_INPUT" ]]; then | |
| VERSION_NAME="manual-build" | |
| else | |
| VERSION_NAME="$VERSION_NAME_INPUT" | |
| fi | |
| DEPLOY_TARGET="internal" | |
| IS_TAG_BUILD="false" | |
| echo "Manual build: $VERSION_NAME -> internal testing" | |
| fi | |
| echo "version_name=$VERSION_NAME" >> $GITHUB_OUTPUT | |
| echo "deploy_target=$DEPLOY_TARGET" >> $GITHUB_OUTPUT | |
| echo "is_tag_build=$IS_TAG_BUILD" >> $GITHUB_OUTPUT | |
| - name: Set Version | |
| uses: chkfung/android-version-actions@fcf89abef1c7afba2083146dcca0c6da4705ba4b | |
| with: | |
| gradlePath: app/build.gradle.kts | |
| versionCode: ${{ github.run_number }} | |
| versionName: ${{ steps.version.outputs.version_name }} | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: "17" | |
| distribution: "temurin" | |
| - name: Cache Gradle dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.gradle/caches | |
| ~/.gradle/wrapper | |
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | |
| restore-keys: | | |
| ${{ runner.os }}-gradle- | |
| save: false | |
| lookup-only: true | |
| - name: Grant execute permission for gradlew | |
| run: chmod +x gradlew | |
| - name: Build prod release APK and AAB | |
| run: | | |
| ./gradlew assembleProdRelease bundleProdRelease | |
| env: | |
| SIGNING_KEY_BASE64: ${{ secrets.SIGNING_KEY }} | |
| KEY_ALIAS: ${{ secrets.KEY_ALIAS }} | |
| KEY_STORE_PASSWORD: ${{ secrets.KEY_STORE_PASSWORD }} | |
| KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} | |
| - name: Prepare release artifacts | |
| id: artifacts | |
| run: | | |
| # Find the generated files (Gradle handles the naming) | |
| APK_PATH=$(find app/build/outputs/apk/prod/release -name "*.apk" | head -1) | |
| AAB_PATH=$(find app/build/outputs/bundle/prodRelease -name "*.aab" | head -1) | |
| # Extract the actual filenames generated by Gradle | |
| APK_NAME=$(basename "$APK_PATH") | |
| AAB_NAME=$(basename "$AAB_PATH") | |
| echo "apk_path=$APK_PATH" >> $GITHUB_OUTPUT | |
| echo "aab_path=$AAB_PATH" >> $GITHUB_OUTPUT | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coffee-shot-timer-${{ steps.version.outputs.version_name }} | |
| path: | | |
| ${{ steps.artifacts.outputs.apk_path }} | |
| ${{ steps.artifacts.outputs.aab_path }} | |
| - name: Generate GitHub release notes | |
| id: gen_release_notes | |
| env: | |
| VERSION_NAME_OUTPUT: ${{ steps.version.outputs.version_name }} | |
| IS_TAG_BUILD_OUTPUT: ${{ steps.version.outputs.is_tag_build }} | |
| run: | | |
| set -euo pipefail | |
| VERSION_NAME="$VERSION_NAME_OUTPUT" | |
| IS_TAG_BUILD="$IS_TAG_BUILD_OUTPUT" | |
| NOTES_FILE="RELEASE_NOTES.md" | |
| if [[ ! -f CHANGELOG.md ]]; then | |
| echo "ERROR: CHANGELOG.md not found." | |
| exit 1 | |
| fi | |
| # Extract notes for tag builds from the matching version section, otherwise from [Unreleased] | |
| if [[ "$IS_TAG_BUILD" == "true" ]]; then | |
| awk -v v="$VERSION_NAME" ' | |
| BEGIN{p=0} | |
| /^## \[/{ | |
| if (p==1) exit | |
| if ($0 ~ "^## \\[(" v ")\\]") p=1 | |
| } | |
| p==1{print} | |
| ' CHANGELOG.md | sed '1d' | sed '/^## \[/Q' > "$NOTES_FILE" | |
| else | |
| awk ' | |
| BEGIN{p=0} | |
| /^## \[/{ | |
| if (p==1) exit | |
| if ($0 ~ /^## \[Unreleased\]/) p=1 | |
| } | |
| p==1{print} | |
| ' CHANGELOG.md | sed '1d' | sed '/^## \[/Q' > "$NOTES_FILE" | |
| fi | |
| # Fail if notes are empty after extraction | |
| if [[ ! -s "$NOTES_FILE" ]]; then | |
| echo "ERROR: Release notes are empty. Ensure the appropriate section exists in CHANGELOG.md." | |
| exit 1 | |
| fi | |
| echo "notes_file=$NOTES_FILE" >> $GITHUB_OUTPUT | |
| - name: Print extracted release notes | |
| env: | |
| NOTES_FILE_OUTPUT: ${{ steps.gen_release_notes.outputs.notes_file }} | |
| run: | | |
| echo "=== Extracted release notes ($NOTES_FILE_OUTPUT) ===" | |
| cat "$NOTES_FILE_OUTPUT" | |
| echo "=== End of release notes ===" | |
| - name: Create or update GitHub release | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| VERSION_NAME_OUTPUT: ${{ steps.version.outputs.version_name }} | |
| IS_TAG_BUILD_OUTPUT: ${{ steps.version.outputs.is_tag_build }} | |
| APK_PATH_OUTPUT: ${{ steps.artifacts.outputs.apk_path }} | |
| AAB_PATH_OUTPUT: ${{ steps.artifacts.outputs.aab_path }} | |
| NOTES_FILE_OUTPUT: ${{ steps.gen_release_notes.outputs.notes_file }} | |
| run: | | |
| VERSION_NAME="$VERSION_NAME_OUTPUT" | |
| IS_TAG_BUILD="$IS_TAG_BUILD_OUTPUT" | |
| APK_PATH="$APK_PATH_OUTPUT" | |
| AAB_PATH="$AAB_PATH_OUTPUT" | |
| NOTES_FILE="$NOTES_FILE_OUTPUT" | |
| if [[ "$IS_TAG_BUILD" == "true" ]]; then | |
| # Tag build - create new release | |
| TAG_NAME="v${VERSION_NAME}" | |
| RELEASE_TITLE="Coffee Shot Timer v${VERSION_NAME}" | |
| echo "Creating tag release: $TAG_NAME" | |
| gh release create "$TAG_NAME" \ | |
| --title "$RELEASE_TITLE" \ | |
| --notes-file "$NOTES_FILE" \ | |
| "$APK_PATH" \ | |
| "$AAB_PATH" | |
| echo "Created release: $RELEASE_TITLE" | |
| else | |
| # Main branch build - replace existing main release | |
| RELEASE_TAG="main-latest" | |
| RELEASE_TITLE="Coffee Shot Timer (Latest Main)" | |
| echo "Creating/updating main release: $RELEASE_TAG" | |
| # Delete existing release if it exists | |
| if gh release view "$RELEASE_TAG" > /dev/null 2>&1; then | |
| echo "Deleting existing main release..." | |
| gh release delete "$RELEASE_TAG" --yes | |
| fi | |
| # Create new release | |
| gh release create "$RELEASE_TAG" \ | |
| --title "$RELEASE_TITLE" \ | |
| --notes-file "$NOTES_FILE" \ | |
| --prerelease \ | |
| "$APK_PATH" \ | |
| "$AAB_PATH" | |
| echo "Created/updated main release: $RELEASE_TITLE" | |
| fi | |
| - name: Prepare Play Store what's new (en-US) | |
| id: play_whatsnew | |
| env: | |
| VERSION_NAME_OUTPUT: ${{ steps.version.outputs.version_name }} | |
| IS_TAG_BUILD_OUTPUT: ${{ steps.version.outputs.is_tag_build }} | |
| run: | | |
| set -euo pipefail | |
| VERSION_NAME="$VERSION_NAME_OUTPUT" | |
| IS_TAG_BUILD="$IS_TAG_BUILD_OUTPUT" | |
| WHATSNEW_DIR="whatsnew" | |
| mkdir -p "$WHATSNEW_DIR" | |
| # Determine which version to extract from CHANGELOG.md | |
| if [[ "$IS_TAG_BUILD" == "true" ]]; then | |
| EXTRACT_VERSION="$VERSION_NAME" | |
| else | |
| EXTRACT_VERSION="unreleased" | |
| fi | |
| # Use the extract-whatsnew.sh script to get priority items (or all items if no priorities) | |
| # This extracts items marked with [*] in CHANGELOG.md for Play Store | |
| ./scripts/extract-whatsnew.sh "$EXTRACT_VERSION" 500 > "$WHATSNEW_DIR/whatsnew-en-US" | |
| # Verify the extraction worked | |
| if [[ ! -s "$WHATSNEW_DIR/whatsnew-en-US" ]]; then | |
| echo "ERROR: Failed to extract Play Store release notes from CHANGELOG.md" | |
| exit 1 | |
| fi | |
| # Character count is already enforced by the script (max 500) | |
| CHAR_COUNT=$(wc -m < "$WHATSNEW_DIR/whatsnew-en-US" | tr -d ' ') | |
| echo "Play Store release notes: $CHAR_COUNT characters" | |
| echo "=== Play Store What's New (en-US) ===" | |
| cat "$WHATSNEW_DIR/whatsnew-en-US" | |
| echo "=== End of What's New ===" | |
| echo "whatsnew_dir=$WHATSNEW_DIR" >> $GITHUB_OUTPUT | |
| - name: Deploy to Google Play Console | |
| uses: r0adkll/upload-google-play@935ef9c68bb393a8e6116b1575626a7f5be3a7fb | |
| with: | |
| serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }} | |
| packageName: com.jodli.coffeeshottimer | |
| releaseFiles: ${{ steps.artifacts.outputs.aab_path }} | |
| track: ${{ steps.version.outputs.deploy_target }} | |
| inAppUpdatePriority: 2 | |
| whatsNewDirectory: ${{ steps.play_whatsnew.outputs.whatsnew_dir }} |