✨ feat(capacitor-android): inietta versionName e versionCode da package.json

- Nuovo step "Inject Android version" dopo il sync Capacitor: riscrive versionName e versionCode in android/app/build.gradle prima della build
- versionCode derivato come major*10000 + minor*100 + patch, monotono crescente fra release; pre-release e build metadata scartati dal calcolo ma mantenuti nel versionName
- Nuovo input opzionale version-code per forzare un valore esplicito
- Supporto Groovy e Kotlin DSL; fallisce con diagnostica se la piattaforma manca, la versione non e' semver, minor/patch superano 99 o l'iniezione non produce il valore atteso
- Allineata la variante -github, corpo dello step identico

Fixes #5 @1h30m
This commit is contained in:
LucaZanni
2026-08-11 08:51:01 +02:00
parent c0524722e4
commit cd4929ad5f
2 changed files with 170 additions and 0 deletions
@@ -20,6 +20,10 @@ on:
description: 'apk (sideload/test) | aab (Play Store)' description: 'apk (sideload/test) | aab (Play Store)'
type: string type: string
default: 'apk' default: 'apk'
version-code:
description: 'versionCode Android esplicito. Se vuoto viene derivato da package.json: major*10000 + minor*100 + patch'
type: string
default: ''
secrets: secrets:
NPM_TOKEN: NPM_TOKEN:
required: false required: false
@@ -96,6 +100,87 @@ jobs:
- name: Sync Capacitor - name: Sync Capacitor
run: npx cap sync android run: npx cap sync android
# La piattaforma Android puo essere generata da 'cap add' (default Capacitor:
# versionName "1.0", versionCode 1) oppure versionata nel repo consumer.
# In entrambi i casi la versione pubblicata deve derivare da package.json,
# unica fonte di verita, altrimenti l'APK/AAB dichiara una versione diversa
# da quella del tag e Play Store rifiuta upload con versionCode non crescente.
- name: Inject Android version
id: android-version
env:
PKG_VERSION: ${{ steps.app-info.outputs.version }}
VERSION_CODE_OVERRIDE: ${{ inputs.version-code }}
run: |
set -euo pipefail
if [ -f android/app/build.gradle ]; then
GRADLE_FILE="android/app/build.gradle"
KTS=0
elif [ -f android/app/build.gradle.kts ]; then
GRADLE_FILE="android/app/build.gradle.kts"
KTS=1
else
echo "::error::Nessun build.gradle in android/app/ — piattaforma Android non generata"
exit 1
fi
VERSION_NAME="$PKG_VERSION"
if [ -n "$VERSION_CODE_OVERRIDE" ]; then
VERSION_CODE="$VERSION_CODE_OVERRIDE"
else
CORE="${PKG_VERSION%%-*}" # scarta il pre-release: 1.2.3-beta.1 -> 1.2.3
CORE="${CORE%%+*}" # scarta il build metadata: 1.2.3+abc -> 1.2.3
MAJOR="$(echo "$CORE" | cut -d. -f1)"
MINOR="$(echo "$CORE" | cut -d. -f2)"
PATCH="$(echo "$CORE" | cut -d. -f3)"
MINOR="${MINOR:-0}"
PATCH="${PATCH:-0}"
case "${MAJOR}${MINOR}${PATCH}" in
''|*[!0-9]*)
echo "::error::Versione package.json non semver: '$PKG_VERSION'. Passare version-code esplicito."
exit 1
;;
esac
if [ "$MINOR" -gt 99 ] || [ "$PATCH" -gt 99 ]; then
echo "::error::minor/patch > 99 non rappresentabili ('$PKG_VERSION'). Passare version-code esplicito."
exit 1
fi
VERSION_CODE=$(( MAJOR * 10000 + MINOR * 100 + PATCH ))
fi
if [ "$KTS" -eq 1 ]; then
sed -i -E "s/versionCode[[:space:]]*=[[:space:]]*[0-9]+/versionCode = ${VERSION_CODE}/" "$GRADLE_FILE"
sed -i -E "s/versionName[[:space:]]*=[[:space:]]*\"[^\"]*\"/versionName = \"${VERSION_NAME}\"/" "$GRADLE_FILE"
else
sed -i -E "s/versionCode[[:space:]]+[0-9]+/versionCode ${VERSION_CODE}/" "$GRADLE_FILE"
sed -i -E "s/versionName[[:space:]]+\"[^\"]*\"/versionName \"${VERSION_NAME}\"/" "$GRADLE_FILE"
fi
# Il sed silenzioso e' peggio di un fallimento: senza questa verifica una
# variazione del template Capacitor produrrebbe build con versione sbagliata.
# Si confrontano i valori estratti, non si rilegge il file con una regex
# costruita sulla versione: '+' e '.' di un semver sono metacaratteri ERE.
# '|| true': senza, pipefail farebbe uscire lo step su un file privo di
# versionCode/versionName, perdendo la diagnostica del blocco sottostante.
ACTUAL_CODE="$(grep -oE 'versionCode[[:space:]]*=?[[:space:]]*[0-9]+' "$GRADLE_FILE" | head -1 | grep -oE '[0-9]+$' || true)"
ACTUAL_NAME="$(grep -oE 'versionName[[:space:]]*=?[[:space:]]*"[^"]*"' "$GRADLE_FILE" | head -1 | cut -d'"' -f2 || true)"
if [ "$ACTUAL_CODE" != "$VERSION_CODE" ] || [ "$ACTUAL_NAME" != "$VERSION_NAME" ]; then
echo "::error::Iniezione versione fallita in $GRADLE_FILE"
echo " atteso: versionName='${VERSION_NAME}' versionCode=${VERSION_CODE}"
echo " trovato: versionName='${ACTUAL_NAME}' versionCode=${ACTUAL_CODE}"
grep -nE 'versionCode|versionName' "$GRADLE_FILE" || true
exit 1
fi
echo "version-name=${VERSION_NAME}" >> $GITHUB_OUTPUT
echo "version-code=${VERSION_CODE}" >> $GITHUB_OUTPUT
echo "Android: versionName=${VERSION_NAME} versionCode=${VERSION_CODE} ($GRADLE_FILE)"
- name: Setup google-services.json - name: Setup google-services.json
if: secrets.GOOGLE_SERVICES_JSON != '' if: secrets.GOOGLE_SERVICES_JSON != ''
run: echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > android/app/google-services.json run: echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > android/app/google-services.json
+85
View File
@@ -20,6 +20,10 @@ on:
description: 'apk (sideload/test) | aab (Play Store)' description: 'apk (sideload/test) | aab (Play Store)'
type: string type: string
default: 'apk' default: 'apk'
version-code:
description: 'versionCode Android esplicito. Se vuoto viene derivato da package.json: major*10000 + minor*100 + patch'
type: string
default: ''
secrets: secrets:
NPM_TOKEN: NPM_TOKEN:
required: false required: false
@@ -96,6 +100,87 @@ jobs:
- name: Sync Capacitor - name: Sync Capacitor
run: npx cap sync android run: npx cap sync android
# La piattaforma Android puo essere generata da 'cap add' (default Capacitor:
# versionName "1.0", versionCode 1) oppure versionata nel repo consumer.
# In entrambi i casi la versione pubblicata deve derivare da package.json,
# unica fonte di verita, altrimenti l'APK/AAB dichiara una versione diversa
# da quella del tag e Play Store rifiuta upload con versionCode non crescente.
- name: Inject Android version
id: android-version
env:
PKG_VERSION: ${{ steps.app-info.outputs.version }}
VERSION_CODE_OVERRIDE: ${{ inputs.version-code }}
run: |
set -euo pipefail
if [ -f android/app/build.gradle ]; then
GRADLE_FILE="android/app/build.gradle"
KTS=0
elif [ -f android/app/build.gradle.kts ]; then
GRADLE_FILE="android/app/build.gradle.kts"
KTS=1
else
echo "::error::Nessun build.gradle in android/app/ — piattaforma Android non generata"
exit 1
fi
VERSION_NAME="$PKG_VERSION"
if [ -n "$VERSION_CODE_OVERRIDE" ]; then
VERSION_CODE="$VERSION_CODE_OVERRIDE"
else
CORE="${PKG_VERSION%%-*}" # scarta il pre-release: 1.2.3-beta.1 -> 1.2.3
CORE="${CORE%%+*}" # scarta il build metadata: 1.2.3+abc -> 1.2.3
MAJOR="$(echo "$CORE" | cut -d. -f1)"
MINOR="$(echo "$CORE" | cut -d. -f2)"
PATCH="$(echo "$CORE" | cut -d. -f3)"
MINOR="${MINOR:-0}"
PATCH="${PATCH:-0}"
case "${MAJOR}${MINOR}${PATCH}" in
''|*[!0-9]*)
echo "::error::Versione package.json non semver: '$PKG_VERSION'. Passare version-code esplicito."
exit 1
;;
esac
if [ "$MINOR" -gt 99 ] || [ "$PATCH" -gt 99 ]; then
echo "::error::minor/patch > 99 non rappresentabili ('$PKG_VERSION'). Passare version-code esplicito."
exit 1
fi
VERSION_CODE=$(( MAJOR * 10000 + MINOR * 100 + PATCH ))
fi
if [ "$KTS" -eq 1 ]; then
sed -i -E "s/versionCode[[:space:]]*=[[:space:]]*[0-9]+/versionCode = ${VERSION_CODE}/" "$GRADLE_FILE"
sed -i -E "s/versionName[[:space:]]*=[[:space:]]*\"[^\"]*\"/versionName = \"${VERSION_NAME}\"/" "$GRADLE_FILE"
else
sed -i -E "s/versionCode[[:space:]]+[0-9]+/versionCode ${VERSION_CODE}/" "$GRADLE_FILE"
sed -i -E "s/versionName[[:space:]]+\"[^\"]*\"/versionName \"${VERSION_NAME}\"/" "$GRADLE_FILE"
fi
# Il sed silenzioso e' peggio di un fallimento: senza questa verifica una
# variazione del template Capacitor produrrebbe build con versione sbagliata.
# Si confrontano i valori estratti, non si rilegge il file con una regex
# costruita sulla versione: '+' e '.' di un semver sono metacaratteri ERE.
# '|| true': senza, pipefail farebbe uscire lo step su un file privo di
# versionCode/versionName, perdendo la diagnostica del blocco sottostante.
ACTUAL_CODE="$(grep -oE 'versionCode[[:space:]]*=?[[:space:]]*[0-9]+' "$GRADLE_FILE" | head -1 | grep -oE '[0-9]+$' || true)"
ACTUAL_NAME="$(grep -oE 'versionName[[:space:]]*=?[[:space:]]*"[^"]*"' "$GRADLE_FILE" | head -1 | cut -d'"' -f2 || true)"
if [ "$ACTUAL_CODE" != "$VERSION_CODE" ] || [ "$ACTUAL_NAME" != "$VERSION_NAME" ]; then
echo "::error::Iniezione versione fallita in $GRADLE_FILE"
echo " atteso: versionName='${VERSION_NAME}' versionCode=${VERSION_CODE}"
echo " trovato: versionName='${ACTUAL_NAME}' versionCode=${ACTUAL_CODE}"
grep -nE 'versionCode|versionName' "$GRADLE_FILE" || true
exit 1
fi
echo "version-name=${VERSION_NAME}" >> $GITHUB_OUTPUT
echo "version-code=${VERSION_CODE}" >> $GITHUB_OUTPUT
echo "Android: versionName=${VERSION_NAME} versionCode=${VERSION_CODE} ($GRADLE_FILE)"
- name: Setup google-services.json - name: Setup google-services.json
if: secrets.GOOGLE_SERVICES_JSON != '' if: secrets.GOOGLE_SERVICES_JSON != ''
run: echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > android/app/google-services.json run: echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > android/app/google-services.json