bump version 1.1.0 #2
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: Create GitHub Release | |
| on: | |
| workflow_dispatch: | |
| push: | |
| branches: | |
| - main | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: github-release-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| release: | |
| name: Build APKs And Create Release | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| env: | |
| RELEASE_KEYSTORE_BASE64: ${{ secrets.RELEASE_KEYSTORE_BASE64 }} | |
| RELEASE_KEYSTORE_PASSWORD: ${{ secrets.RELEASE_KEYSTORE_PASSWORD }} | |
| RELEASE_KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }} | |
| RELEASE_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Read ProjectConfig version | |
| id: version | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| version_name="$(sed -n 's/^[[:space:]]*const val VERSION_NAME = "\([^"]*\)".*/\1/p' buildSrc/src/main/kotlin/BuildConfig.kt | head -n 1)" | |
| if [ -z "$version_name" ]; then | |
| echo "::error::Unable to read ProjectConfig.VERSION_NAME from buildSrc/src/main/kotlin/BuildConfig.kt." | |
| exit 1 | |
| fi | |
| echo "version_name=$version_name" >> "$GITHUB_OUTPUT" | |
| echo "tag_name=v$version_name" >> "$GITHUB_OUTPUT" | |
| if [[ "$version_name" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| echo "is_release=true" >> "$GITHUB_OUTPUT" | |
| echo "Detected formal release version: $version_name" | |
| else | |
| echo "is_release=false" >> "$GITHUB_OUTPUT" | |
| echo "::notice::ProjectConfig.VERSION_NAME is '$version_name', not strict x.y.z. Skipping tag and release creation." | |
| fi | |
| - name: Skip non-release version | |
| if: steps.version.outputs.is_release != 'true' | |
| run: echo "No GitHub Release will be created for version '${{ steps.version.outputs.version_name }}'." | |
| - name: Make Gradle wrapper executable | |
| if: steps.version.outputs.is_release == 'true' | |
| run: chmod +x ./gradlew | |
| - name: Set up JDK | |
| if: steps.version.outputs.is_release == 'true' | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: "25" | |
| - name: Set up Gradle | |
| if: steps.version.outputs.is_release == 'true' | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Set up Android SDK | |
| if: steps.version.outputs.is_release == 'true' | |
| uses: android-actions/setup-android@v3 | |
| - name: Install Android SDK packages | |
| if: steps.version.outputs.is_release == 'true' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| set +o pipefail | |
| yes | sdkmanager --licenses >/dev/null | |
| licenses_status="${PIPESTATUS[1]}" | |
| set -o pipefail | |
| if [ "$licenses_status" -ne 0 ]; then | |
| echo "::error::Failed to accept Android SDK licenses." | |
| exit "$licenses_status" | |
| fi | |
| target_sdk="$(sed -n 's/^[[:space:]]*const val TARGET_SDK = \([0-9]\+\).*/\1/p' buildSrc/src/main/kotlin/BuildConfig.kt | head -n 1)" | |
| if [ -z "$target_sdk" ]; then | |
| echo "::error::Unable to read ProjectConfig.TARGET_SDK from buildSrc/src/main/kotlin/BuildConfig.kt." | |
| exit 1 | |
| fi | |
| available_packages="$(sdkmanager --list | awk '{ print $1 }')" | |
| platform_package="platforms;android-${target_sdk}" | |
| if ! grep -Fxq "$platform_package" <<< "$available_packages"; then | |
| if grep -Fxq "platforms;android-${target_sdk}.0" <<< "$available_packages"; then | |
| platform_package="platforms;android-${target_sdk}.0" | |
| else | |
| echo "::error::No Android SDK platform package is available for TARGET_SDK=$target_sdk." | |
| exit 1 | |
| fi | |
| fi | |
| build_tools_package="$(printf '%s\n' "$available_packages" | awk '$1 ~ /^build-tools;[0-9]/ { print $1 }' | sort -V | tail -n 1)" | |
| ndk_package="$(printf '%s\n' "$available_packages" | awk '$1 ~ /^ndk;[0-9]/ { print $1 }' | sort -V | tail -n 1)" | |
| if [ -z "$build_tools_package" ]; then | |
| echo "::error::No Android build-tools package is available from sdkmanager." | |
| exit 1 | |
| fi | |
| if [ -z "$ndk_package" ]; then | |
| echo "::error::No Android NDK package is available from sdkmanager." | |
| exit 1 | |
| fi | |
| sdkmanager --install "$platform_package" "$build_tools_package" "$ndk_package" | |
| ndk_version="${ndk_package#ndk;}" | |
| echo "ANDROID_NDK_HOME=$ANDROID_HOME/ndk/$ndk_version" >> "$GITHUB_ENV" | |
| echo "ANDROID_NDK_ROOT=$ANDROID_HOME/ndk/$ndk_version" >> "$GITHUB_ENV" | |
| - name: Validate signing secrets | |
| if: steps.version.outputs.is_release == 'true' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [ -z "${RELEASE_KEYSTORE_BASE64:-}" ]; then | |
| echo "::error::Missing repository secret RELEASE_KEYSTORE_BASE64." | |
| exit 1 | |
| fi | |
| if [ -z "${RELEASE_KEYSTORE_PASSWORD:-}" ]; then | |
| echo "::error::Missing repository secret RELEASE_KEYSTORE_PASSWORD." | |
| exit 1 | |
| fi | |
| if [ -z "${RELEASE_KEY_ALIAS:-}" ]; then | |
| echo "::error::Missing repository secret RELEASE_KEY_ALIAS." | |
| exit 1 | |
| fi | |
| - name: Build release APKs | |
| if: steps.version.outputs.is_release == 'true' | |
| run: ./gradlew --no-daemon :app:assembleRelease | |
| - name: Sign release APKs | |
| if: steps.version.outputs.is_release == 'true' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| keystore_path="$RUNNER_TEMP/release.keystore" | |
| printf '%s' "$RELEASE_KEYSTORE_BASE64" | base64 --decode > "$keystore_path" | |
| key_password="${RELEASE_KEY_PASSWORD:-$RELEASE_KEYSTORE_PASSWORD}" | |
| export RELEASE_KEYSTORE_PASSWORD | |
| export RELEASE_KEY_PASSWORD="$key_password" | |
| zipalign="$(find "$ANDROID_HOME/build-tools" -type f -name zipalign | sort -V | tail -n 1)" | |
| apksigner="$(find "$ANDROID_HOME/build-tools" -type f -name apksigner | sort -V | tail -n 1)" | |
| if [ -z "$zipalign" ]; then | |
| echo "::error::zipalign was not found in Android build-tools." | |
| exit 1 | |
| fi | |
| if [ -z "$apksigner" ]; then | |
| echo "::error::apksigner was not found in Android build-tools." | |
| exit 1 | |
| fi | |
| mkdir -p signed-apks | |
| shopt -s nullglob | |
| for apk in app/build/outputs/apk/release/*.apk; do | |
| base_name="$(basename "$apk" .apk)" | |
| aligned_apk="$RUNNER_TEMP/${base_name}-aligned.apk" | |
| signed_apk="signed-apks/${base_name}-signed.apk" | |
| "$zipalign" -p -f 4 "$apk" "$aligned_apk" | |
| "$apksigner" sign \ | |
| --ks "$keystore_path" \ | |
| --ks-pass env:RELEASE_KEYSTORE_PASSWORD \ | |
| --ks-key-alias "$RELEASE_KEY_ALIAS" \ | |
| --key-pass env:RELEASE_KEY_PASSWORD \ | |
| --out "$signed_apk" \ | |
| "$aligned_apk" | |
| "$apksigner" verify --verbose "$signed_apk" | |
| done | |
| if ! find signed-apks -type f -name "*.apk" | grep -q .; then | |
| echo "::error::No signed release APKs were produced." | |
| exit 1 | |
| fi | |
| - name: Collect release APKs | |
| if: steps.version.outputs.is_release == 'true' | |
| id: collect | |
| shell: bash | |
| env: | |
| VERSION_NAME: ${{ steps.version.outputs.version_name }} | |
| run: | | |
| set -euo pipefail | |
| version_code="$(git rev-list --count HEAD)" | |
| mkdir -p release-artifacts | |
| shopt -s nullglob | |
| for apk in signed-apks/*.apk; do | |
| file_name="$(basename "$apk")" | |
| abi="universal" | |
| case "$file_name" in | |
| *arm64-v8a*) abi="arm64-v8a" ;; | |
| *armeabi-v7a*) abi="armeabi-v7a" ;; | |
| *x86_64*) abi="x86_64" ;; | |
| *x86*) abi="x86" ;; | |
| *universal*) abi="universal" ;; | |
| esac | |
| cp "$apk" "release-artifacts/AsteriskNG_${VERSION_NAME}-${version_code}-${abi}.apk" | |
| done | |
| if ! find release-artifacts -type f -name "*.apk" | grep -q .; then | |
| echo "::error::No release APKs were found under signed-apks." | |
| exit 1 | |
| fi | |
| if ! find release-artifacts -type f -name "*-universal.apk" | grep -q .; then | |
| echo "::error::The universal APK was not produced." | |
| find release-artifacts -maxdepth 1 -type f -name "*.apk" -print | |
| exit 1 | |
| fi | |
| echo "version_code=$version_code" >> "$GITHUB_OUTPUT" | |
| ls -lh release-artifacts | |
| - name: Upload GitHub artifact | |
| if: steps.version.outputs.is_release == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: AsteriskNG_${{ steps.version.outputs.version_name }}-${{ steps.collect.outputs.version_code }} | |
| path: release-artifacts/*.apk | |
| if-no-files-found: error | |
| - name: Create tag and release notes | |
| if: steps.version.outputs.is_release == 'true' | |
| id: release_info | |
| shell: bash | |
| env: | |
| TAG_NAME: ${{ steps.version.outputs.tag_name }} | |
| VERSION_NAME: ${{ steps.version.outputs.version_name }} | |
| VERSION_CODE: ${{ steps.collect.outputs.version_code }} | |
| run: | | |
| set -euo pipefail | |
| current_sha="$(git rev-parse HEAD)" | |
| git fetch --tags --force | |
| if git rev-parse -q --verify "refs/tags/$TAG_NAME" >/dev/null; then | |
| tag_sha="$(git rev-list -n 1 "$TAG_NAME")" | |
| if [ "$tag_sha" != "$current_sha" ]; then | |
| echo "::error::Tag $TAG_NAME already exists at $tag_sha, but this workflow is running at $current_sha." | |
| exit 1 | |
| fi | |
| echo "Tag $TAG_NAME already exists on the current commit." | |
| else | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git tag -a "$TAG_NAME" -m "Release $TAG_NAME" "$current_sha" | |
| git push origin "refs/tags/$TAG_NAME" | |
| fi | |
| mapfile -t release_tags < <( | |
| git for-each-ref --format='%(refname:short)' refs/tags | | |
| grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' || true | |
| ) | |
| previous_candidates="$(mktemp)" | |
| for candidate in "${release_tags[@]}"; do | |
| if [ "$candidate" = "$TAG_NAME" ]; then | |
| continue | |
| fi | |
| if git merge-base --is-ancestor "$candidate" "$current_sha"; then | |
| count="$(git rev-list --count "${candidate}..${current_sha}")" | |
| printf '%s\t%s\n' "$count" "$candidate" >> "$previous_candidates" | |
| fi | |
| done | |
| previous_tag="" | |
| if [ -s "$previous_candidates" ]; then | |
| previous_tag="$(sort -n "$previous_candidates" | head -n 1 | cut -f2-)" | |
| fi | |
| range="$current_sha" | |
| if [ -n "$previous_tag" ]; then | |
| range="${previous_tag}..${current_sha}" | |
| fi | |
| tmp_changes="$(mktemp)" | |
| git log --reverse --no-merges --pretty=format:"- %s ([%h](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commit/%H))" "$range" > "$tmp_changes" | |
| if [ ! -s "$tmp_changes" ]; then | |
| git log --reverse --pretty=format:"- %s ([%h](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commit/%H))" "$range" > "$tmp_changes" | |
| fi | |
| { | |
| echo "## AsteriskNG $TAG_NAME" | |
| echo | |
| echo "- Version name: $VERSION_NAME" | |
| echo "- Version code: $VERSION_CODE" | |
| echo | |
| if [ -n "$previous_tag" ]; then | |
| echo "### Changes since $previous_tag" | |
| echo | |
| echo "[Compare $previous_tag...$TAG_NAME](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/compare/${previous_tag}...${TAG_NAME})" | |
| else | |
| echo "### Changes" | |
| fi | |
| echo | |
| if [ -s "$tmp_changes" ]; then | |
| cat "$tmp_changes" | |
| echo | |
| else | |
| echo "- No commit changes found." | |
| fi | |
| echo | |
| echo "### APK artifacts" | |
| echo | |
| find release-artifacts -maxdepth 1 -type f -name "*.apk" -printf "- %f\n" | sort | |
| } > release-notes.md | |
| echo "previous_tag=$previous_tag" >> "$GITHUB_OUTPUT" | |
| cat release-notes.md | |
| - name: Create GitHub Release | |
| if: steps.version.outputs.is_release == 'true' | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TAG_NAME: ${{ steps.version.outputs.tag_name }} | |
| VERSION_NAME: ${{ steps.version.outputs.version_name }} | |
| run: | | |
| set -euo pipefail | |
| if gh release view "$TAG_NAME" >/dev/null 2>&1; then | |
| gh release upload "$TAG_NAME" release-artifacts/*.apk --clobber | |
| gh release edit "$TAG_NAME" \ | |
| --title "AsteriskNG $TAG_NAME" \ | |
| --notes-file release-notes.md \ | |
| --latest | |
| else | |
| gh release create "$TAG_NAME" release-artifacts/*.apk \ | |
| --title "AsteriskNG $TAG_NAME" \ | |
| --notes-file release-notes.md \ | |
| --latest | |
| fi |