fix: remove redundant 'needs' declaration in build-and-release job #14
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: 🚀 Build and Release Android | ||
|
Check failure on line 1 in .github/workflows/publish.yml
|
||
| on: | ||
| push: | ||
| branches: [ main ] | ||
| permissions: | ||
| contents: write | ||
| issues: write | ||
| pull-requests: write | ||
| jobs: | ||
| # ───────────────────────────────────────────── | ||
| # Job 1 — Resolve the next semantic version | ||
| # Runs semantic-release in dry-run mode so we | ||
| # know the version before the build starts. | ||
| # ───────────────────────────────────────────── | ||
| resolve-version: | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| version: ${{ steps.semver.outputs.version }} | ||
| version_code: ${{ steps.semver.outputs.version_code }} | ||
| will_release: ${{ steps.semver.outputs.will_release }} | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: "lts/*" | ||
| - name: Install semantic-release | ||
| run: | | ||
| npm install --save-dev semantic-release \ | ||
| @semantic-release/changelog \ | ||
| @semantic-release/git \ | ||
| @semantic-release/github \ | ||
| conventional-changelog-conventionalcommits | ||
| - name: Write .releaserc.json (dry-run config) | ||
| run: | | ||
| cat > .releaserc.json << 'EOF' | ||
| { | ||
| "branches": ["main"], | ||
| "plugins": [ | ||
| ["@semantic-release/commit-analyzer", { "preset": "conventionalcommits" }], | ||
| ["@semantic-release/release-notes-generator", { "preset": "conventionalcommits" }] | ||
| ] | ||
| } | ||
| EOF | ||
| - name: Determine next version (dry-run) | ||
| id: semver | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| # semantic-release exits 1 when no release is triggered — that's not an | ||
| # error for us, so we capture the exit code manually instead of letting | ||
| # bash -e kill the step. | ||
| set +e | ||
| OUTPUT=$(npx semantic-release --dry-run --no-ci 2>&1) | ||
| SR_EXIT=$? | ||
| set -e | ||
| echo "$OUTPUT" | ||
| echo "--- semantic-release exit code: $SR_EXIT ---" | ||
| VERSION=$(echo "$OUTPUT" | grep -oP 'The next release version is \K[0-9]+\.[0-9]+\.[0-9]+' | head -1) | ||
| # Exit code 2+ means a real error (bad config, auth failure, etc.) | ||
| if [ $SR_EXIT -ge 2 ]; then | ||
| echo "❌ semantic-release failed with exit code $SR_EXIT" | ||
| exit $SR_EXIT | ||
| fi | ||
| if [ -z "$VERSION" ]; then | ||
| echo "⚠️ No release triggered — using last tag or 1.0.0" | ||
| VERSION=$(git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//' || echo "1.0.0") | ||
| echo "will_release=false" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "will_release=true" >> $GITHUB_OUTPUT | ||
| fi | ||
| # versionCode: major*10000 + minor*100 + patch (e.g. 1.2.3 → 10203) | ||
| MAJOR=$(echo "$VERSION" | cut -d. -f1) | ||
| MINOR=$(echo "$VERSION" | cut -d. -f2) | ||
| PATCH=$(echo "$VERSION" | cut -d. -f3) | ||
| VERSION_CODE=$(( MAJOR * 10000 + MINOR * 100 + PATCH )) | ||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||
| echo "version_code=$VERSION_CODE" >> $GITHUB_OUTPUT | ||
| echo "✅ Version: $VERSION (code: $VERSION_CODE)" | ||
| # ───────────────────────────────────────────── | ||
| # Job 2 — Build & release | ||
| # Uses the version resolved above. | ||
| # ───────────────────────────────────────────── | ||
| build-and-release: | ||
| runs-on: ubuntu-latest | ||
| needs: resolve-version | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| - name: Set up JDK 21 | ||
| uses: actions/setup-java@v4 | ||
| with: | ||
| java-version: '21' | ||
| distribution: 'temurin' | ||
| cache: gradle | ||
| - name: Setup Android SDK | ||
| uses: android-actions/setup-android@v3 | ||
| - name: Cache Gradle dependencies | ||
| uses: actions/cache@v3 | ||
| with: | ||
| path: | | ||
| ~/.gradle/caches | ||
| ~/.gradle/wrapper | ||
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-gradle- | ||
| - name: Cache Android build | ||
| uses: actions/cache@v3 | ||
| with: | ||
| path: | | ||
| ~/.android/build-cache | ||
| app/build | ||
| key: ${{ runner.os }}-android-${{ hashFiles('**/build.gradle*', '**/gradle.properties', '**/settings.gradle*') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-android- | ||
| - name: Cache Kotlin | ||
| uses: actions/cache@v3 | ||
| with: | ||
| path: | | ||
| ~/.kotlin/cache | ||
| ~/.konan | ||
| key: ${{ runner.os }}-kotlin-${{ hashFiles('**/*.kt', '**/*.kts') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-kotlin- | ||
| - name: Make gradlew executable | ||
| run: chmod +x ./gradlew | ||
| - name: Decode Keystore | ||
| run: | | ||
| echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > $RUNNER_TEMP/release.keystore | ||
| - name: Build Release APK + AAB (signed, versioned) | ||
| env: | ||
| VERSION: ${{ needs.resolve-version.outputs.version }} | ||
| VERSION_CODE: ${{ needs.resolve-version.outputs.version_code }} | ||
| KEYSTORE_PATH: ${{ runner.temp }}/release.keystore | ||
| KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} | ||
| KEY_ALIAS: ${{ secrets.KEY_ALIAS }} | ||
| KEY_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} | ||
| - name: Build Release APK + AAB (signed, versioned) | ||
| env: | ||
| VERSION: ${{ needs.resolve-version.outputs.version }} | ||
| VERSION_CODE: ${{ needs.resolve-version.outputs.version_code }} | ||
| KEYSTORE_PATH: ${{ runner.temp }}/release.keystore | ||
| KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} | ||
| KEY_ALIAS: ${{ secrets.KEY_ALIAS }} | ||
| KEY_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} | ||
| run: | | ||
| echo "🏗️ Building v$VERSION (code $VERSION_CODE)" | ||
| echo "🏗️ Building v$VERSION (code $VERSION_CODE)" | ||
| ./gradlew assembleRelease bundleRelease \ | ||
| -PversionName="$VERSION" \ | ||
| -PversionCode="$VERSION_CODE" \ | ||
| -PversionName="$VERSION" \ | ||
| -PversionCode="$VERSION_CODE" \ | ||
| -Pandroid.injected.signing.store.file=$RUNNER_TEMP/release.keystore \ | ||
| -Pandroid.injected.signing.store.password=${{ secrets.KEYSTORE_PASSWORD }} \ | ||
| -Pandroid.injected.signing.key.alias=${{ secrets.KEY_ALIAS }} \ | ||
| -Pandroid.injected.signing.key.password=${{ secrets.KEYSTORE_PASSWORD }} \ | ||
| --build-cache | ||
| - name: Rename and verify outputs | ||
| id: outputs | ||
| env: | ||
| VERSION: ${{ needs.resolve-version.outputs.version }} | ||
| - name: Rename and verify outputs | ||
| id: outputs | ||
| env: | ||
| VERSION: ${{ needs.resolve-version.outputs.version }} | ||
| run: | | ||
| APK_SRC="app/build/outputs/apk/release/app-release.apk" | ||
| AAB_SRC="app/build/outputs/bundle/release/app-release.aab" | ||
| [ ! -f "$APK_SRC" ] && APK_SRC=$(find app/build/outputs -name "*release*.apk" -type f | head -1) | ||
| [ ! -f "$AAB_SRC" ] && AAB_SRC=$(find app/build/outputs -name "*release*.aab" -type f | head -1) | ||
| if [ -z "$APK_SRC" ] || [ ! -f "$APK_SRC" ]; then echo "❌ APK release non trouvé"; exit 1; fi | ||
| if [ -z "$AAB_SRC" ] || [ ! -f "$AAB_SRC" ]; then echo "❌ AAB release non trouvé"; exit 1; fi | ||
| APK_OUT="app/build/outputs/apk/release/app-release-v${VERSION}.apk" | ||
| AAB_OUT="app/build/outputs/bundle/release/app-release-v${VERSION}.aab" | ||
| mv "$APK_SRC" "$APK_OUT" | ||
| mv "$AAB_SRC" "$AAB_OUT" | ||
| echo "APK_PATH=$APK_OUT" >> $GITHUB_OUTPUT | ||
| echo "AAB_PATH=$AAB_OUT" >> $GITHUB_OUTPUT | ||
| echo "✅ APK: $APK_OUT" | ||
| echo "✅ AAB: $AAB_OUT" | ||
| APK_SRC="app/build/outputs/apk/release/app-release.apk" | ||
| AAB_SRC="app/build/outputs/bundle/release/app-release.aab" | ||
| [ ! -f "$APK_SRC" ] && APK_SRC=$(find app/build/outputs -name "*release*.apk" -type f | head -1) | ||
| [ ! -f "$AAB_SRC" ] && AAB_SRC=$(find app/build/outputs -name "*release*.aab" -type f | head -1) | ||
| if [ -z "$APK_SRC" ] || [ ! -f "$APK_SRC" ]; then echo "❌ APK release non trouvé"; exit 1; fi | ||
| if [ -z "$AAB_SRC" ] || [ ! -f "$AAB_SRC" ]; then echo "❌ AAB release non trouvé"; exit 1; fi | ||
| APK_OUT="app/build/outputs/apk/release/app-release-v${VERSION}.apk" | ||
| AAB_OUT="app/build/outputs/bundle/release/app-release-v${VERSION}.aab" | ||
| mv "$APK_SRC" "$APK_OUT" | ||
| mv "$AAB_SRC" "$AAB_OUT" | ||
| echo "APK_PATH=$APK_OUT" >> $GITHUB_OUTPUT | ||
| echo "AAB_PATH=$AAB_OUT" >> $GITHUB_OUTPUT | ||
| echo "✅ APK: $APK_OUT" | ||
| echo "✅ AAB: $AAB_OUT" | ||
| - name: Setup Node.js for semantic-release | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: "lts/*" | ||
| - name: Install semantic-release and plugins | ||
| run: | | ||
| npm install --save-dev semantic-release \ | ||
| @semantic-release/changelog \ | ||
| @semantic-release/git \ | ||
| @semantic-release/github \ | ||
| conventional-changelog-conventionalcommits | ||
| - name: Write .releaserc.json (real release with assets) | ||
| env: | ||
| APK_PATH: ${{ steps.outputs.outputs.APK_PATH }} | ||
| AAB_PATH: ${{ steps.outputs.outputs.AAB_PATH }} | ||
| VERSION: ${{ needs.resolve-version.outputs.version }} | ||
| run: | | ||
| cat > .releaserc.json << EOF | ||
| { | ||
| "branches": ["main"], | ||
| "plugins": [ | ||
| ["@semantic-release/commit-analyzer", { "preset": "conventionalcommits" }], | ||
| ["@semantic-release/release-notes-generator", { "preset": "conventionalcommits" }], | ||
| "@semantic-release/changelog", | ||
| ["@semantic-release/github", { | ||
| "assets": [ | ||
| { | ||
| "path": "${APK_PATH}", | ||
| "name": "app-release-v${VERSION}.apk", | ||
| "label": "Android APK v${VERSION} (universal)" | ||
| }, | ||
| { | ||
| "path": "${AAB_PATH}", | ||
| "name": "app-release-v${VERSION}.aab", | ||
| "label": "Android App Bundle v${VERSION} (Play Store)" | ||
| } | ||
| ] | ||
| }], | ||
| ["@semantic-release/git", { | ||
| "assets": ["CHANGELOG.md"], | ||
| "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" | ||
| }] | ||
| ] | ||
| } | ||
| EOF | ||
| - name: Run semantic-release | ||
| - name: Write .releaserc.json (real release with assets) | ||
| env: | ||
| APK_PATH: ${{ steps.outputs.outputs.APK_PATH }} | ||
| AAB_PATH: ${{ steps.outputs.outputs.AAB_PATH }} | ||
| VERSION: ${{ needs.resolve-version.outputs.version }} | ||
| run: | | ||
| cat > .releaserc.json << EOF | ||
| { | ||
| "branches": ["main"], | ||
| "plugins": [ | ||
| ["@semantic-release/commit-analyzer", { "preset": "conventionalcommits" }], | ||
| ["@semantic-release/release-notes-generator", { "preset": "conventionalcommits" }], | ||
| "@semantic-release/changelog", | ||
| ["@semantic-release/github", { | ||
| "assets": [ | ||
| { | ||
| "path": "${APK_PATH}", | ||
| "name": "app-release-v${VERSION}.apk", | ||
| "label": "Android APK v${VERSION} (universal)" | ||
| }, | ||
| { | ||
| "path": "${AAB_PATH}", | ||
| "name": "app-release-v${VERSION}.aab", | ||
| "label": "Android App Bundle v${VERSION} (Play Store)" | ||
| } | ||
| ] | ||
| }], | ||
| ["@semantic-release/git", { | ||
| "assets": ["CHANGELOG.md"], | ||
| "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" | ||
| }] | ||
| ] | ||
| } | ||
| EOF | ||
| - name: Run semantic-release | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: npx semantic-release | ||
| # - name: Publish AAB to Play Store | ||
| # uses: r0adkll/upload-google-play@v1 | ||
| # with: | ||
| # serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }} | ||
| # packageName: com.bob1.app | ||
| # releaseFiles: ${{ steps.outputs.outputs.AAB_PATH }} | ||
| # packageName: com.bob1.app | ||
| # releaseFiles: ${{ steps.outputs.outputs.AAB_PATH }} | ||
| # track: internal | ||
| # status: completed | ||
| - name: Upload APK artifact | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: bob1-apk | ||
| path: ${{ steps.outputs.outputs.APK_PATH }} | ||
| name: bob1-apk | ||
| path: ${{ steps.outputs.outputs.APK_PATH }} | ||
| retention-days: 30 | ||
| - name: Upload AAB artifact | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: bob1-aab | ||
| path: ${{ steps.outputs.outputs.AAB_PATH }} | ||
| path: ${{ steps.outputs.outputs.AAB_PATH }} | ||
| retention-days: 30 | ||