Skip to content

Toss Multi-Platform Build and Release Workflow #3

Toss Multi-Platform Build and Release Workflow

Toss Multi-Platform Build and Release Workflow #3

Workflow file for this run

name: Toss Multi-Platform Build and Release Workflow
on:
workflow_dispatch:
jobs:
get-latest-tag:
name: Get Latest and Previous Git Tags
runs-on: ubuntu-latest
outputs:
latest_tag: ${{ steps.tags.outputs.latest_tag }}
previous_tag: ${{ steps.tags.outputs.previous_tag }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Determine tags
id: tags
run: |
git fetch --tags
latest_tag=$(git tag --sort=-version:refname | head -n1)
previous_tag=$(git tag --sort=-version:refname | sed -n '2p')
echo "latest_tag=$latest_tag" >> "$GITHUB_OUTPUT"
echo "previous_tag=$previous_tag" >> "$GITHUB_OUTPUT"
windows-build:
name: Build for Windows (Inno Setup)
runs-on: windows-latest
needs: get-latest-tag
outputs:
windows_artifact: ${{ steps.upload_windows.outputs.artifact_path }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Fix flutter SDK folder permission
run: git config --global --add safe.directory %TEMP%/flutter/--
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.29.2'
- name: Install dependencies
run: flutter pub get
- name: Build Windows app
run: flutter build windows --release
- name: Install Inno Setup
run: choco install innosetup -y
- name: Create Inno Setup script
run: |
echo '; Inno Setup script to package the Flutter app' > package.iss
echo '[Setup]' >> package.iss
echo 'Compression=zip' >> package.iss
echo 'AppName=Toss' >> package.iss
echo "AppVersion=${{ needs.get-latest-tag.outputs.latest_tag }}" >> package.iss
echo 'DefaultDirName={pf}\Toss' >> package.iss
echo 'DefaultGroupName=Toss' >> package.iss
echo 'OutputBaseFilename=TossInstaller' >> package.iss
echo '[Files]' >> package.iss
echo 'Source: "build\windows\x64\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs' >> package.iss
echo '[Icons]' >> package.iss
echo 'Name: "{group}\Toss"; Filename: "{app}\toss.exe"' >> package.iss
- name: Create Installer
run: iscc package.iss
- name: Upload Installer
id: upload_windows
uses: actions/upload-artifact@v4
with:
name: Toss-Windows-Installer
path: Output/TossInstaller.exe
linux-build:
name: Build for Linux (AppImage)
runs-on: ubuntu-latest
needs: get-latest-tag
outputs:
linux_artifact: ${{ steps.upload_linux.outputs.artifact_path }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install apt dependencies
run: |
sudo apt-get update
sudo apt install -y clang cmake curl git ninja-build pkg-config unzip xz-utils zip libgtk-3-dev liblzma-dev libsecret-1-dev
- name: Fix flutter SDK folder permission
run: git config --global --add safe.directory /tmp/flutter/--
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.29.2'
- name: Install dependencies
run: flutter pub get
- name: Build Linux app
run: flutter build linux --release
- name: Install AppImageTool
run: |
wget https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
chmod +x appimagetool-x86_64.AppImage
- name: Package as AppImage
run: |
mkdir -p AppDir/usr/bin
cp -r build/linux/x64/release/bundle/* AppDir/usr/bin
chmod +x AppDir/usr/bin/toss
# Create .desktop file using printf to avoid indentation problems
mkdir -p AppDir
printf '%s\n' \
'[Desktop Entry]' \
'Type=Application' \
'Name=Toss' \
'Exec=toss' \
'Icon=toss' \
'Categories=Utility;' > AppDir/toss.desktop
# Copy icon (must match Icon=toss and be .png)
cp assets/icons/icon.png AppDir/toss.png
./appimagetool-x86_64.AppImage AppDir Toss.AppImage
- name: Upload AppImage
id: upload_linux
uses: actions/upload-artifact@v4
with:
name: Toss-Linux-AppImage
path: Toss.AppImage
android-build:
name: Build for Android (APK)
runs-on: ubuntu-latest
needs: get-latest-tag
outputs:
android_artifact: ${{ steps.upload_android.outputs.artifact_path }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Fix flutter SDK folder permission
run: git config --global --add safe.directory /tmp/flutter/--
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.29.2'
- name: Install dependencies
run: flutter pub get
- name: Build Android APK
run: flutter build apk --release
- name: Upload APK
id: upload_android
uses: actions/upload-artifact@v4
with:
name: Toss-Android-APK
path: build/app/outputs/flutter-apk/app-release.apk
ios-build:
name: Trigger iOS Build on Codemagic
runs-on: ubuntu-latest
needs: get-latest-tag
outputs:
build_id: ${{ steps.trigger_build.outputs.build_id }}
steps:
- name: Trigger Codemagic iOS Build
id: trigger_build
run: |
RESPONSE=$(curl -s -X POST \
-H "Content-Type: application/json" \
-H "x-auth-token: ${{ secrets.CODEMAGIC_TOKEN }}" \
-d '{
"appId": "68048cb2df9d43bf817c1eaa",
"workflowId": "68048cb2df9d43bf817c1ea9",
"branch": "master",
"environment": {
"TAG_NAME": "${{ needs.get-latest-tag.outputs.latest_tag }}"
}
}' \
https://api.codemagic.io/builds)
echo "$RESPONSE"
BUILD_ID=$(echo "$RESPONSE" | jq -r '.buildId')
if [ -z "$BUILD_ID" ] || [ "$BUILD_ID" == "null" ]; then
echo "Failed to trigger build"
exit 1
fi
echo "build_id=${BUILD_ID}" >> "$GITHUB_OUTPUT"
wait-for-codemagic:
name: Wait for Codemagic Build to Complete
runs-on: ubuntu-latest
needs: ios-build
outputs:
build_status: ${{ steps.check_status.outputs.status }}
steps:
- name: Poll Codemagic Build Status
id: check_status
run: |
BUILD_ID=${{ needs.ios-build.outputs.build_id }}
echo "Polling status for build ID: $BUILD_ID"
for i in {1..100}; do
STATUS=$(curl -s -H "x-auth-token: ${{ secrets.CODEMAGIC_TOKEN }}" \
"https://api.codemagic.io/builds/$BUILD_ID" | jq -r '.build.status')
echo "Status: $STATUS"
if [[ "$STATUS" == "finished" ]]; then
echo "Build completed."
echo "status=success" >> "$GITHUB_OUTPUT"
exit 0
elif [[ "$STATUS" == "failed" || "$STATUS" == "canceled" ]]; then
echo "Build failed or canceled."
echo "status=failed" >> "$GITHUB_OUTPUT"
exit 1
fi
sleep 10
done
echo "Timed out waiting for build to finish"
exit 1
fetch-codemagic-artifacts:
name: Fetch IPA from Codemagic
runs-on: ubuntu-latest
needs: [ios-build, wait-for-codemagic]
outputs:
codemagic_artifact: ${{ steps.upload_codemagic.outputs.artifact_path }}
steps:
- name: Get .ipa Artifact URL
id: get_artifact_url
run: |
BUILD_ID=${{ needs.ios-build.outputs.build_id }}
BUILD_JSON=$(curl -s -H "x-auth-token: ${{ secrets.CODEMAGIC_TOKEN }}" \
"https://api.codemagic.io/builds/$BUILD_ID")
echo "$BUILD_JSON" > build_info.json
IPA_URL=$(echo "$BUILD_JSON" | jq -r '.build.artefacts[] | select(.name | endswith(".ipa")) | .url')
if [ -z "$IPA_URL" ] || [ "$IPA_URL" == "null" ]; then
echo "No IPA artifact found."
exit 1
fi
echo "IPA_URL=$IPA_URL" >> $GITHUB_ENV
- name: Download .ipa
run: |
curl -L -o Toss.ipa "$IPA_URL"
- name: Upload IPA
id: upload_codemagic
uses: actions/upload-artifact@v4
with:
name: Toss-iOS-IPA
path: Toss.ipa
create-release:
needs:
- windows-build
- linux-build
- android-build
- fetch-codemagic-artifacts
- get-latest-tag
runs-on: ubuntu-latest
steps:
- name: Download Windows Installer
uses: actions/download-artifact@v4
with:
name: Toss-Windows-Installer
- name: Download Linux AppImage
uses: actions/download-artifact@v4
with:
name: Toss-Linux-AppImage
- name: Download Android APK
uses: actions/download-artifact@v4
with:
name: Toss-Android-APK
- name: Rename APK
run: mv app-release.apk Toss.apk
- name: Download iOS IPA
uses: actions/download-artifact@v4
with:
name: Toss-iOS-IPA
- name: Generate release body
id: release_body
run: |
# Start with the changelog link
echo "**Full Changelog**: https://github.com/Slipstreamm/Toss/compare/${{ needs.get-latest-tag.outputs.previous_tag }}...${{ needs.get-latest-tag.outputs.latest_tag }}" > release_body.md
echo "" >> release_body.md
echo "## SHA256 Hashes" >> release_body.md
# Compute and append the SHA256 for each artifact
for file in TossInstaller.exe Toss.AppImage Toss.apk Toss.ipa; do
HASH=$(sha256sum "$file" | awk '{print $1}')
echo "- $file: \`$HASH\`" >> release_body.md
done
- name: Create/Update GitHub Release and Upload Assets
uses: ncipollo/release-action@v1
with:
tag: ${{ needs.get-latest-tag.outputs.latest_tag }}
artifacts: |
TossInstaller.exe
Toss.AppImage
Toss.apk
Toss.ipa
bodyFile: release_body.md
allowUpdates: true # update if the tag already exists
makeLatest: true # force this release to be marked “latest”
prerelease: false
token: ${{ secrets.GITHUB_TOKEN }}