Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Release

on:
push:
tags:
- 'v*'

permissions:
contents: write

jobs:
release:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: gradle

- name: Grant execute permission for gradlew
run: chmod +x gradlew

# Decode the base64-encoded keystore stored in GitHub Secrets and write it
# to a file that Gradle can reference during the signing step.
- name: Decode keystore
run: |
echo "${{ secrets.KEYSTORE_FILE }}" | base64 --decode > ${{ github.workspace }}/release.jks
chmod 600 ${{ github.workspace }}/release.jks
Comment on lines +31 to +34
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

release.jks and keystore.properties remain on disk for the rest of the job. Consider removing them immediately after bundleRelease (or in a final cleanup step with if: always()) to reduce the chance of accidental exposure via later steps/artifacts/logs.

Copilot uses AI. Check for mistakes.

# Write keystore.properties so that app/build.gradle.kts can pick up
# all signing credentials at build time (mirrors keystore.properties.template).
- name: Write keystore.properties
run: |
cat > ${{ github.workspace }}/keystore.properties <<EOF
storeFile=${{ github.workspace }}/release.jks
storePassword=${{ secrets.KEYSTORE_PASSWORD }}
keyAlias=${{ secrets.KEY_ALIAS }}
keyPassword=${{ secrets.KEY_PASSWORD }}
EOF
chmod 600 ${{ github.workspace }}/keystore.properties
Comment on lines +39 to +46
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The here-doc used to write keystore.properties allows shell expansion inside the heredoc body. If any secret contains $, backticks, or escape sequences (common in passwords), the resulting properties file can be corrupted (e.g., $$ becomes PID). Write the file in a way that prevents shell interpolation (e.g., quote the heredoc delimiter or write via printf using env vars).

Suggested change
run: |
cat > ${{ github.workspace }}/keystore.properties <<EOF
storeFile=${{ github.workspace }}/release.jks
storePassword=${{ secrets.KEYSTORE_PASSWORD }}
keyAlias=${{ secrets.KEY_ALIAS }}
keyPassword=${{ secrets.KEY_PASSWORD }}
EOF
chmod 600 ${{ github.workspace }}/keystore.properties
env:
WORKSPACE: ${{ github.workspace }}
STORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: |
printf '%s\n' \
"storeFile=$WORKSPACE/release.jks" \
"storePassword=$STORE_PASSWORD" \
"keyAlias=$KEY_ALIAS" \
"keyPassword=$KEY_PASSWORD" \
> "$WORKSPACE/keystore.properties"
chmod 600 "$WORKSPACE/keystore.properties"

Copilot uses AI. Check for mistakes.

- name: Run unit tests
run: ./gradlew test

- name: Build signed release AAB
run: ./gradlew bundleRelease

- name: Upload AAB artifact
uses: actions/upload-artifact@v4
with:
name: app-release
path: app/build/outputs/bundle/release/app-release.aab
if-no-files-found: error
retention-days: 7

# Creates a GitHub Release and attaches the signed AAB.
# The release name and body are derived from the pushed tag automatically.
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
files: app/build/outputs/bundle/release/app-release.aab

# Uploads the signed AAB to the Internal testing track of the Play Store.
# Change 'track' to 'production' when you are ready for full rollout.
- name: Upload to Google Play (Internal track)
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }}
packageName: fr.benju.tasks
releaseFiles: app/build/outputs/bundle/release/app-release.aab
track: internal