Application Release #144
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: Application Release | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version to bump" | |
| required: true | |
| type: choice | |
| default: "none" | |
| options: | |
| - none | |
| - major | |
| - minor | |
| - patch | |
| - pre | |
| - release | |
| release_title: | |
| description: "Release title" | |
| type: string | |
| required: false | |
| dry_run: | |
| description: "Build and validate without publishing" | |
| type: boolean | |
| default: false | |
| env: | |
| VERSION_BUMP: ${{ github.event.inputs.version }} | |
| RELEASE_TITLE: ${{ github.event.inputs.release_title }} | |
| DRY_RUN: ${{ github.event.inputs.dry_run }} | |
| jobs: | |
| android-build: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: setup actions | |
| uses: actions/checkout@v6 | |
| - name: Setup Java | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: "adopt" | |
| java-version: "17" | |
| - name: parse flutter version | |
| run: | | |
| export FLUTTER_VERSION=$(./.github/workflows/get_flutter_version.sh) | |
| echo "FLUTTER_VERSION=$FLUTTER_VERSION" >> $GITHUB_ENV | |
| - name: setup flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| cache: true | |
| - name: cache flutter dependencies | |
| uses: actions/cache@v5 | |
| with: | |
| path: ${{ env.PUB_CACHE }} | |
| key: ${{ runner.os }}-flutter-${{ hashFiles('**/pubspec.lock') }} | |
| restore-keys: ${{ runner.os }}-flutter- | |
| - name: get flutter dependencies | |
| run: flutter pub get | |
| - name: bump version | |
| if: ${{ github.event.inputs.version != 'none' }} | |
| run: | | |
| dart pub global activate cider | |
| cider bump ${{ env.VERSION_BUMP }} --bump-build | |
| - name: configure release keys | |
| env: | |
| KEYSTORE: ${{ secrets.KEYSTORE }} | |
| KEYCONFIG: ${{ secrets.KEYCONFIG }} | |
| run: | | |
| mkdir -p android/keys | |
| echo "$KEYSTORE" | base64 -d > android/keys/key.pkcs | |
| echo "$KEYCONFIG" | base64 -d > android/keys/key.properties | |
| - name: build APK | |
| run: flutter build apk | |
| - name: build AAB | |
| run: flutter build appbundle | |
| - name: package release | |
| run: | | |
| mv build/app/outputs/apk/release/app-universal-release.apk app-universal-release.apk | |
| mv build/app/outputs/apk/release/app-arm64-v8a-release.apk app-arm64-v8a-release.apk | |
| mv build/app/outputs/apk/release/app-armeabi-v7a-release.apk app-armeabi-v7a-release.apk | |
| mv build/app/outputs/bundle/release/app-release.aab app-release.aab | |
| - name: upload Universal APK to artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: release-apk-universal | |
| path: app-universal-release.apk | |
| - name: upload ARM64 APK to artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: release-apk-arm64 | |
| path: app-arm64-v8a-release.apk | |
| - name: upload ARMv7 APK to artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: release-apk-armv7 | |
| path: app-armeabi-v7a-release.apk | |
| - name: upload AAB to artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: release-aab | |
| path: app-release.aab | |
| ios-build: | |
| runs-on: macos-latest | |
| steps: | |
| - name: setup actions | |
| uses: actions/checkout@v6 | |
| - name: parse flutter version | |
| run: | | |
| export FLUTTER_VERSION=$(./.github/workflows/get_flutter_version.sh) | |
| echo "FLUTTER_VERSION=$FLUTTER_VERSION" >> $GITHUB_ENV | |
| - name: setup flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| cache: true | |
| - name: cache flutter dependencies | |
| uses: actions/cache@v5 | |
| with: | |
| path: ${{ env.PUB_CACHE }} | |
| key: ${{ runner.os }}-flutter-${{ hashFiles('**/pubspec.lock') }} | |
| restore-keys: ${{ runner.os }}-flutter- | |
| - name: get flutter dependencies | |
| run: flutter pub get | |
| - name: bump version | |
| if: ${{ github.event.inputs.version != 'none' }} | |
| run: | | |
| dart pub global activate cider | |
| cider bump ${{ env.VERSION_BUMP }} --bump-build | |
| - name: build IPA | |
| run: flutter build ios --no-codesign | |
| - name: package release | |
| run: | | |
| cd build/ios/iphoneos | |
| mkdir Payload | |
| mv Runner.app Payload/Runner.app | |
| zip -9 -r Runner.zip Payload | |
| mv Runner.zip ../../../Runner.ipa | |
| - name: upload IPA to artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: release-ios | |
| path: Runner.ipa | |
| release: | |
| needs: [android-build, ios-build] | |
| if: ${{ github.ref == 'refs/heads/master' && github.event.inputs.version != 'none' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: setup actions | |
| uses: actions/checkout@v6 | |
| - name: setup ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: "3.1" | |
| bundler-cache: true | |
| - name: parse flutter version | |
| run: | | |
| export FLUTTER_VERSION=$(./.github/workflows/get_flutter_version.sh) | |
| echo "FLUTTER_VERSION=$FLUTTER_VERSION" >> $GITHUB_ENV | |
| - name: setup flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| cache: true | |
| - name: setup cider | |
| run: dart pub global activate cider | |
| - name: bump and release version | |
| run: | | |
| cider bump ${{ env.VERSION_BUMP }} --bump-build | |
| cider release | |
| - name: get new version | |
| run: echo "VERSION=$(cider version)" >> $GITHUB_ENV | |
| - name: get new build number | |
| run: | | |
| VERSION=${{ env.VERSION }} | |
| BUILD_NUMBER=${VERSION#*+} | |
| echo "BUILD_NUMBER=$BUILD_NUMBER" >> $GITHUB_ENV | |
| - name: write playstore changelogs | |
| run: bundle exec fastlane android changelog | |
| - name: commit version increase | |
| if: ${{ github.event.inputs.dry_run != 'true' }} | |
| uses: EndBug/add-and-commit@v9 | |
| with: | |
| message: increased version | |
| default_author: github_actions | |
| add: | | |
| pubspec.yaml | |
| CHANGELOG.md | |
| fastlane | |
| - name: download Universal APK from artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: release-apk-universal | |
| - name: download ARM64 APK from artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: release-apk-arm64 | |
| - name: download ARMv7 APK from artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: release-apk-armv7 | |
| - name: download AAB from artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: release-aab | |
| - name: download IPA from artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: release-ios | |
| - name: arrange asset files | |
| run: | | |
| mkdir -p build/app/outputs/bundle/release | |
| mv app-release.aab build/app/outputs/bundle/release/ | |
| mv app-universal-release.apk e1547-universal.apk | |
| mv app-arm64-v8a-release.apk e1547-arm64.apk | |
| mv app-armeabi-v7a-release.apk e1547-armv7.apk | |
| mv Runner.ipa e1547.ipa | |
| - name: configure playstore keys | |
| env: | |
| KEYSTORE: ${{ secrets.PLAYSTORE }} | |
| run: | | |
| mkdir -p android/keys | |
| echo "$KEYSTORE" > android/keys/playstore.json | |
| - name: publish to Play Store | |
| run: bundle exec fastlane android upload validate_only:${{ github.event.inputs.dry_run }} | |
| - name: create release | |
| if: ${{ github.event.inputs.dry_run != 'true' }} | |
| uses: softprops/action-gh-release@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| tag_name: ${{ env.VERSION }} | |
| name: ${{ env.RELEASE_TITLE }} | |
| body_path: ./fastlane/metadata/android/en-US/changelogs/${{ env.BUILD_NUMBER }}.txt | |
| files: | | |
| e1547-universal.apk | |
| e1547-arm64.apk | |
| e1547-armv7.apk | |
| e1547.ipa | |
| forum-publish: | |
| needs: [release] | |
| if: ${{ github.ref == 'refs/heads/master' && github.event.inputs.version != 'none' && github.event.inputs.dry_run != 'true' }} | |
| runs-on: ubuntu-latest | |
| env: | |
| DMARK_VERSION: '0.0.6' | |
| steps: | |
| - name: setup actions | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: master | |
| - name: setup node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '22' | |
| - name: setup dart | |
| uses: dart-lang/setup-dart@v1 | |
| - name: setup cider | |
| run: dart pub global activate cider | |
| - name: extract release metadata | |
| id: meta | |
| run: | | |
| VERSION=$(cider version) | |
| BUILD_NUMBER=${VERSION#*+} | |
| TOPIC_ID=$(grep -oP "forumTopicId:\s*\K\d+" lib/app/data/initialize.dart) | |
| GITHUB_SLUG=$(grep -oP "github:\s*'\K[^']+" lib/app/data/initialize.dart) | |
| DISCORD_INVITE=$(grep -oP "discord:\s*'\K[^']+" lib/app/data/initialize.dart) | |
| DEVELOPER=$(grep -oP "developer:\s*'\K[^']+" lib/app/data/initialize.dart) | |
| PACKAGE_NAME=$(grep -oP 'applicationId\s*=\s*"\K[^"]+' android/app/build.gradle.kts) | |
| { | |
| echo "version=$VERSION" | |
| echo "build_number=$BUILD_NUMBER" | |
| echo "topic_id=$TOPIC_ID" | |
| echo "github_slug=$GITHUB_SLUG" | |
| echo "discord_invite=$DISCORD_INVITE" | |
| echo "developer=$DEVELOPER" | |
| echo "package_name=$PACKAGE_NAME" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: extract version changelog markdown | |
| run: | | |
| cider describe --only-body "${{ steps.meta.outputs.version }}" \ | |
| > version_changelog.md | |
| - name: download dmark | |
| run: | | |
| curl -fsSL \ | |
| "https://libs.cdn.clynamic.net/dmark/${DMARK_VERSION}/dmark.js" \ | |
| -o dmark.mjs | |
| - name: convert markdown to dtext | |
| run: | | |
| cat > convert.mjs <<'EOF' | |
| import { parseMarkdown, formatDText } from './dmark.mjs'; | |
| import { readFileSync, writeFileSync } from 'node:fs'; | |
| const md = readFileSync('version_changelog.md', 'utf8'); | |
| const parsed = parseMarkdown(md); | |
| const out = formatDText(parsed.document); | |
| writeFileSync('version_changelog.dtext', out.output); | |
| EOF | |
| node convert.mjs | |
| - name: assemble forum post body | |
| run: | | |
| VERSION='${{ steps.meta.outputs.version }}' | |
| PACKAGE_NAME='${{ steps.meta.outputs.package_name }}' | |
| GITHUB_SLUG='${{ steps.meta.outputs.github_slug }}' | |
| DISCORD_INVITE='${{ steps.meta.outputs.discord_invite }}' | |
| { | |
| echo "h1. Version $VERSION" | |
| echo "" | |
| echo "[section,expanded=Changes]" | |
| cat version_changelog.dtext | |
| echo "[/section]" | |
| echo "" | |
| echo "[section,expanded=Download]" | |
| echo "You can download the app in the [b]\"Playstore\":https://play.google.com/store/apps/details?id=$PACKAGE_NAME [/b]" | |
| echo "or get your own copy from the [b]\"Github releases\":https://github.com/$GITHUB_SLUG/releases [/b]." | |
| echo "[/section]" | |
| echo "" | |
| echo "[section,expanded=Community]" | |
| echo "If you have feature suggestions or bugs, join us on the \"discord server\":https://discord.gg/$DISCORD_INVITE " | |
| echo "[/section]" | |
| echo "" | |
| echo "Regards." | |
| } > body.dtext | |
| - name: post to e621 forum | |
| env: | |
| E621_FORUM_USER: ${{ secrets.E621_FORUM_USER }} | |
| E621_FORUM_API_KEY: ${{ secrets.E621_FORUM_API_KEY }} | |
| run: | | |
| PAYLOAD=$(jq -n \ | |
| --arg body "$(cat body.dtext)" \ | |
| --argjson topic_id ${{ steps.meta.outputs.topic_id }} \ | |
| '{forum_post: {topic_id: $topic_id, body: $body}}') | |
| curl -fsS -X POST 'https://e621.net/forum_posts.json' \ | |
| -u "$E621_FORUM_USER:$E621_FORUM_API_KEY" \ | |
| -H "User-Agent: e1547/${{ steps.meta.outputs.version }} (${{ steps.meta.outputs.developer }})" \ | |
| -H "Content-Type: application/json" \ | |
| -d "$PAYLOAD" |