[beta] Second beta release #50
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 & Release (dev) | |
| on: | |
| push: | |
| branches: | |
| - main | |
| jobs: | |
| build-android: | |
| name: Build Android APK | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: '17' | |
| - uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: '3.41.9' | |
| channel: stable | |
| - name: Install dependencies | |
| run: flutter pub get | |
| - name: Prepare signing keystore | |
| env: | |
| ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} | |
| KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} | |
| KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} | |
| KEY_ALIAS: ${{ secrets.KEY_ALIAS || 'release' }} | |
| run: | | |
| if [ -z "$ANDROID_KEYSTORE_BASE64" ]; then | |
| echo "Missing ANDROID_KEYSTORE_BASE64 in GitHub Secrets." | |
| exit 1 | |
| fi | |
| if [ -z "$KEYSTORE_PASSWORD" ] || [ -z "$KEY_PASSWORD" ]; then | |
| echo "Missing KEYSTORE_PASSWORD or KEY_PASSWORD in GitHub Secrets." | |
| exit 1 | |
| fi | |
| TEMP_KEYSTORE_PATH="$(mktemp)" | |
| trap 'rm -f "$TEMP_KEYSTORE_PATH"' EXIT | |
| if ! echo "$ANDROID_KEYSTORE_BASE64" | base64 --decode > "$TEMP_KEYSTORE_PATH"; then | |
| echo "Failed to decode ANDROID_KEYSTORE_BASE64. Verify it is valid base64 in GitHub Secrets." | |
| exit 1 | |
| fi | |
| if ! mv "$TEMP_KEYSTORE_PATH" android/app-release.jks; then | |
| echo "Failed to write decoded keystore to android/app-release.jks. Verify the android directory is writable." | |
| exit 1 | |
| fi | |
| if ! printf '%s\n' "$KEYSTORE_PASSWORD" | keytool -list -keystore android/app-release.jks >/dev/null 2>&1; then | |
| rm -f android/app-release.jks | |
| echo "Keystore validation failed. Verify android/app-release.jks is a readable keystore file and KEYSTORE_PASSWORD is correct for it." | |
| exit 1 | |
| fi | |
| if ! printf '%s\n' "$KEYSTORE_PASSWORD" | keytool -list -keystore android/app-release.jks -alias "$KEY_ALIAS" >/dev/null 2>&1; then | |
| rm -f android/app-release.jks | |
| echo "Keystore alias validation failed. Verify KEY_ALIAS exists in the configured keystore." | |
| exit 1 | |
| fi | |
| chmod 600 android/app-release.jks | |
| umask 077 | |
| printf 'storePassword=%s\nkeyPassword=%s\nkeyAlias=%s\nstoreFile=app-release.jks\n' \ | |
| "$KEYSTORE_PASSWORD" "$KEY_PASSWORD" "$KEY_ALIAS" > android/key.properties | |
| chmod 600 android/key.properties | |
| - name: Build APK | |
| run: flutter build apk --release | |
| - uses: actions/upload-artifact@v6 | |
| with: | |
| name: android-apk | |
| path: build/app/outputs/flutter-apk/app-release.apk | |
| build-windows: | |
| name: Build Windows EXE | |
| runs-on: windows-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: '3.41.9' | |
| channel: stable | |
| - name: Setup CMake 3.x | |
| uses: jwlawson/actions-setup-cmake@v2 | |
| with: | |
| cmake-version: '3.31.6' | |
| - name: Install dependencies | |
| run: flutter pub get | |
| - name: Build Windows | |
| run: flutter build windows --release | |
| env: | |
| CMAKE_POLICY_VERSION_MINIMUM: "3.5" | |
| - name: Zip Windows build | |
| shell: pwsh | |
| run: | | |
| Compress-Archive -Path build/windows/x64/runner/Release/* -DestinationPath NetherLink-windows.zip | |
| - uses: actions/upload-artifact@v6 | |
| with: | |
| name: windows-zip | |
| path: NetherLink-windows.zip | |
| build-macos: | |
| name: Build macOS DMG | |
| runs-on: macos-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: '3.41.9' | |
| channel: stable | |
| - name: Install dependencies | |
| run: | | |
| cat > pubspec_overrides.yaml <<'EOF' | |
| dependency_overrides: | |
| connectivity_plus: 6.1.4 | |
| EOF | |
| flutter pub get | |
| - name: Build macOS | |
| run: flutter build macos --release | |
| env: | |
| FLUTTER_XCODE_CODE_SIGNING_ALLOWED: "NO" | |
| FLUTTER_XCODE_CODE_SIGN_IDENTITY: "" | |
| FLUTTER_XCODE_CODE_SIGNING_REQUIRED: "NO" | |
| - name: Ad-hoc sign macOS app | |
| run: | | |
| APP_PATH="build/macos/Build/Products/Release/NetherLink.app" | |
| codesign --force --deep --sign - "$APP_PATH" | |
| codesign --verify --deep --strict "$APP_PATH" | |
| - name: Create macOS DMG | |
| run: | | |
| STAGING_DIR="$RUNNER_TEMP/dmg-staging" | |
| APP_PATH="build/macos/Build/Products/Release/NetherLink.app" | |
| rm -rf "$STAGING_DIR" | |
| mkdir -p "$STAGING_DIR" | |
| cp -R "$APP_PATH" "$STAGING_DIR/" | |
| ln -s /Applications "$STAGING_DIR/Applications" | |
| hdiutil create \ | |
| -volname "NetherLink" \ | |
| -srcfolder "$STAGING_DIR" \ | |
| -ov \ | |
| -format UDZO \ | |
| "$GITHUB_WORKSPACE/NetherLink-macos.dmg" | |
| codesign --force --sign - "$GITHUB_WORKSPACE/NetherLink-macos.dmg" | |
| codesign --verify --strict "$GITHUB_WORKSPACE/NetherLink-macos.dmg" | |
| - uses: actions/upload-artifact@v6 | |
| with: | |
| name: macos-dmg | |
| path: NetherLink-macos.dmg | |
| release: | |
| name: Create or Update dev Release | |
| needs: [build-android, build-windows, build-macos] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: android-apk | |
| path: artifacts/ | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: windows-zip | |
| path: artifacts/ | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: macos-dmg | |
| path: artifacts/ | |
| - name: Rename Android APK | |
| run: mv artifacts/app-release.apk artifacts/NetherLink-android.apk | |
| - name: Create or update dev release | |
| uses: softprops/action-gh-release@v3 | |
| with: | |
| tag_name: dev | |
| name: Development Build | |
| prerelease: true | |
| body: | | |
| Automated development build from commit ${{ github.sha }} on branch `${{ github.ref_name }}`. | |
| This is a development build. If you don't know what you are doing, please don't install it. | |
| files: | | |
| artifacts/NetherLink-android.apk | |
| artifacts/NetherLink-windows.zip | |
| artifacts/NetherLink-macos.dmg | |
| notify-discord: | |
| name: Notify Discord | |
| if: ${{ always() }} | |
| needs: [build-android, build-windows, build-macos, release] | |
| runs-on: ubuntu-latest | |
| permissions: {} | |
| steps: | |
| - name: Send build status embed | |
| env: | |
| DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} | |
| ANDROID_RESULT: ${{ needs.build-android.result }} | |
| WINDOWS_RESULT: ${{ needs.build-windows.result }} | |
| MACOS_RESULT: ${{ needs.build-macos.result }} | |
| RELEASE_RESULT: ${{ needs.release.result }} | |
| REPOSITORY: ${{ github.repository }} | |
| BRANCH: ${{ github.ref_name }} | |
| ACTOR: ${{ github.actor }} | |
| SHA: ${{ github.sha }} | |
| COMMIT_MESSAGE: ${{ github.event.head_commit.message }} | |
| RUN_ID: ${{ github.run_id }} | |
| SERVER_URL: ${{ github.server_url }} | |
| RELEASES_URL: ${{ github.server_url }}/${{ github.repository }}/releases | |
| run: | | |
| if [ -z "$DISCORD_WEBHOOK_URL" ]; then | |
| echo "DISCORD_WEBHOOK_URL is not configured. Skipping Discord notification." | |
| exit 0 | |
| fi | |
| OVERALL_STATUS="✅ Build Succeeded" | |
| EMBED_COLOR=5763719 | |
| if [ "$ANDROID_RESULT" != "success" ] || [ "$WINDOWS_RESULT" != "success" ] || [ "$MACOS_RESULT" != "success" ] || [ "$RELEASE_RESULT" != "success" ]; then | |
| OVERALL_STATUS="❌ Build Failed" | |
| EMBED_COLOR=15548997 | |
| fi | |
| RUN_URL="$SERVER_URL/$REPOSITORY/actions/runs/$RUN_ID" | |
| COMMIT_URL="$SERVER_URL/$REPOSITORY/commit/$SHA" | |
| COMMIT_SUBJECT="$(printf '%s' "$COMMIT_MESSAGE" | head -n 1)" | |
| PAYLOAD="$(jq -n \ | |
| --arg overallStatus "$OVERALL_STATUS" \ | |
| --arg repository "$REPOSITORY" \ | |
| --arg branch "$BRANCH" \ | |
| --arg actor "$ACTOR" \ | |
| --arg runUrl "$RUN_URL" \ | |
| --arg commitUrl "$COMMIT_URL" \ | |
| --arg sha "$SHA" \ | |
| --arg commitSubject "$COMMIT_SUBJECT" \ | |
| --arg android "$ANDROID_RESULT" \ | |
| --arg windows "$WINDOWS_RESULT" \ | |
| --arg macos "$MACOS_RESULT" \ | |
| --arg release "$RELEASE_RESULT" \ | |
| --arg releasesUrl "$RELEASES_URL" \ | |
| --argjson color "$EMBED_COLOR" \ | |
| '{ | |
| username: "GitHub Actions", | |
| avatar_url: "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png", | |
| embeds: [ | |
| { | |
| title: $overallStatus, | |
| color: $color, | |
| description: ("**Repository:** `" + $repository + "`\n**Branch:** `" + $branch + "`\n**Triggered by:** `" + $actor + "`"), | |
| author: { | |
| name: "GitHub", | |
| icon_url: "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png" | |
| }, | |
| fields: [ | |
| { name: "Android", value: $android, inline: true }, | |
| { name: "Windows", value: $windows, inline: true }, | |
| { name: "macOS", value: $macos, inline: true }, | |
| { name: "Release", value: $release, inline: true }, | |
| { name: "Commit", value: ("[" + ($sha | .[0:7]) + "](" + $commitUrl + ")" + (if $commitSubject != "" then " " + $commitSubject else "" end)), inline: false }, | |
| { name: "Releases Page", value: ("[View Releases](" + $releasesUrl + ")"), inline: false } | |
| ], | |
| url: $runUrl, | |
| timestamp: now | todateiso8601 | |
| } | |
| ] | |
| }')" | |
| RESPONSE_FILE="$(mktemp)" | |
| HTTP_STATUS="$(curl -sS -o "$RESPONSE_FILE" -w "%{http_code}" -H "Content-Type: application/json" -d "$PAYLOAD" "$DISCORD_WEBHOOK_URL" || true)" | |
| if [ "${HTTP_STATUS:-000}" -lt 200 ] || [ "${HTTP_STATUS:-000}" -ge 300 ]; then | |
| echo "Failed to send Discord notification. HTTP status: ${HTTP_STATUS:-000}" | |
| echo "Response body:" | |
| cat "$RESPONSE_FILE" | |
| exit 1 | |
| fi | |
| rm -f "$RESPONSE_FILE" | |
| notify-discord-beta: | |
| name: Notify Discord Beta Release | |
| needs: [build-android, build-windows, build-macos, release] | |
| if: ${{ needs.build-android.result == 'success' && needs.build-windows.result == 'success' && needs.build-macos.result == 'success' && needs.release.result == 'success' && startsWith(github.event.head_commit.message, '[beta]') }} | |
| runs-on: ubuntu-latest | |
| permissions: {} | |
| steps: | |
| - name: Send beta release embed | |
| env: | |
| DISCORD_BETA_WEBHOOK_URL: ${{ secrets.DISCORD_BETA_WEBHOOK_URL }} | |
| REPOSITORY: ${{ github.repository }} | |
| ACTOR: ${{ github.actor }} | |
| SHA: ${{ github.sha }} | |
| COMMIT_MESSAGE: ${{ github.event.head_commit.message }} | |
| RUN_ID: ${{ github.run_id }} | |
| SERVER_URL: ${{ github.server_url }} | |
| RELEASES_URL: ${{ github.server_url }}/${{ github.repository }}/releases | |
| run: | | |
| if [ -z "$DISCORD_BETA_WEBHOOK_URL" ]; then | |
| echo "DISCORD_BETA_WEBHOOK_URL is not configured. Skipping Discord beta notification." | |
| exit 0 | |
| fi | |
| ROLE_ID="1485783465365344316" | |
| RUN_URL="$SERVER_URL/$REPOSITORY/actions/runs/$RUN_ID" | |
| COMMIT_URL="$SERVER_URL/$REPOSITORY/commit/$SHA" | |
| COMMIT_SUBJECT="$(printf '%s' "$COMMIT_MESSAGE" | head -n 1)" | |
| PAYLOAD="$(jq -n \ | |
| --arg roleId "$ROLE_ID" \ | |
| --arg releasesUrl "$RELEASES_URL" \ | |
| --arg commitUrl "$COMMIT_URL" \ | |
| --arg sha "$SHA" \ | |
| --arg commitSubject "$COMMIT_SUBJECT" \ | |
| --arg runUrl "$RUN_URL" \ | |
| --arg actor "$ACTOR" \ | |
| '{ | |
| content: ("<@&" + $roleId + ">"), | |
| allowed_mentions: { | |
| roles: [$roleId] | |
| }, | |
| username: "GitHub Actions", | |
| avatar_url: "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png", | |
| embeds: [ | |
| { | |
| title: "🚀 New Beta Release Available", | |
| url: $releasesUrl, | |
| color: 5793266, | |
| description: ("Hello, <@&" + $roleId + ">, we have a new beta release ready. Check it out on our [releases](" + $releasesUrl + ")."), | |
| author: { | |
| name: "NetherLink Beta Releases", | |
| icon_url: "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png" | |
| }, | |
| fields: [ | |
| { name: "Commit", value: ("[" + ($sha | .[0:7]) + "](" + $commitUrl + ")" + (if $commitSubject != "" then " " + $commitSubject else "" end)), inline: false }, | |
| { name: "Platforms", value: "Android • Windows • macOS", inline: true }, | |
| { name: "Download links", value: ("[Releases](" + $releasesUrl + ")"), inline: true }, | |
| { name: "Triggered by", value: $actor, inline: true }, | |
| { name: "Workflow", value: ("[View run](" + $runUrl + ")"), inline: true } | |
| ], | |
| footer: { | |
| text: "NetherLink beta release" | |
| }, | |
| timestamp: now | todateiso8601 | |
| } | |
| ] | |
| }')" | |
| RESPONSE_FILE="$(mktemp)" | |
| HTTP_STATUS="$(curl -sS -o "$RESPONSE_FILE" -w "%{http_code}" -H "Content-Type: application/json" -d "$PAYLOAD" "$DISCORD_BETA_WEBHOOK_URL")" | |
| CURL_EXIT_CODE=$? | |
| if [ "$CURL_EXIT_CODE" -ne 0 ]; then | |
| echo "Failed to send Discord beta release notification with curl exit code: $CURL_EXIT_CODE" | |
| exit "$CURL_EXIT_CODE" | |
| fi | |
| if [ "${HTTP_STATUS:-000}" -lt 200 ] || [ "${HTTP_STATUS:-000}" -ge 300 ]; then | |
| echo "Failed to send Discord beta release notification. HTTP status: ${HTTP_STATUS:-000}" | |
| echo "Response body:" | |
| cat "$RESPONSE_FILE" | |
| exit 1 | |
| fi | |
| rm -f "$RESPONSE_FILE" |