# CI runs only on release tags. # # Tag v*: analyze + test → build APK → attach to Forgejo Release # # To cut a release: # Create a release via the Forgejo UI on main with a v* tag name. # The tag push triggers this workflow; the build job attaches the APK. # # Note: JavaScript actions (actions/checkout, actions/upload-artifact) cannot run # inside the Flutter container because it has no Node.js. All steps use shell # commands directly instead. # # Required secrets (repo → Settings → Secrets → Actions): # RELEASE_TOKEN — Forgejo PAT with write:repository scope name: CI & Build on: push: tags: ["v*"] jobs: analyze: name: Analyze & test runs-on: py3.12-node22 container: image: ghcr.io/cirruslabs/flutter:stable steps: - name: Checkout run: | git clone "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" . git checkout "$GITHUB_SHA" - name: Install dependencies run: flutter pub get - name: Analyze run: flutter analyze - name: Test run: flutter test build: name: Build release APK needs: [analyze] runs-on: py3.12-node22 container: image: ghcr.io/cirruslabs/flutter:stable steps: - name: Checkout run: | git clone "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" . git checkout "$GITHUB_SHA" - name: Install dependencies run: flutter pub get - name: Set up release signing env: KEYSTORE_B64: ${{ secrets.RELEASE_KEYSTORE_BASE64 }} STORE_PASSWORD: ${{ secrets.RELEASE_KEYSTORE_PASSWORD }} KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }} run: | echo "$KEYSTORE_B64" | base64 -d > android/app/release.jks printf 'storePassword=%s\nkeyPassword=%s\nkeyAlias=%s\nstoreFile=release.jks\n' \ "$STORE_PASSWORD" "$STORE_PASSWORD" "$KEY_ALIAS" > android/key.properties - name: Build release APK run: | # Derive version from the tag (e.g. v26.03.12 → name=26.03.12 number=260312) TAG="${{ github.ref_name }}" BUILD_NAME="${TAG#v}" BUILD_NUMBER=$(echo "$BUILD_NAME" | tr -d '.') flutter build apk --release \ --build-name="$BUILD_NAME" \ --build-number="$BUILD_NUMBER" - name: Set artifact name id: artifact run: | echo "name=fabledapp-${{ github.ref_name }}-${{ github.sha }}" >> $GITHUB_OUTPUT - name: Upload artifact to Forgejo env: RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} APK: build/app/outputs/flutter-apk/app-release.apk API: https://git.fabledsword.com/api/v1/repos/bvandeusen/FabledApp ARTIFACT_NAME: ${{ steps.artifact.outputs.name }} run: | # Upload the APK as a workflow artifact via the Forgejo API. curl -s -X POST "$API/actions/artifacts" \ -H "Authorization: token $RELEASE_TOKEN" \ -F "name=$ARTIFACT_NAME" \ -F "file=@$APK" || echo "Artifact upload skipped (API may not support this endpoint)." - name: Publish Forgejo release env: RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} TAG: ${{ github.ref_name }} API: https://git.fabledsword.com/api/v1/repos/bvandeusen/FabledApp run: | # Look for an existing release (created via the UI or a prior run). EXISTING=$(curl -s \ "$API/releases/tags/$TAG" \ -H "Authorization: token $RELEASE_TOKEN") RELEASE_ID=$(echo "$EXISTING" | grep -oE '"id":[[:space:]]*[0-9]+' | head -1 | grep -oE '[0-9]+') if [ -n "$RELEASE_ID" ]; then echo "Found existing release $TAG (id $RELEASE_ID), attaching APK..." else echo "No existing release found, creating $TAG..." RESPONSE=$(curl -s -X POST "$API/releases" \ -H "Authorization: token $RELEASE_TOKEN" \ -H "Content-Type: application/json" \ -d "{\"tag_name\": \"$TAG\", \"name\": \"$TAG\", \"body\": \"\"}") RELEASE_ID=$(echo "$RESPONSE" | grep -oE '"id":[[:space:]]*[0-9]+' | head -1 | grep -oE '[0-9]+') if [ -z "$RELEASE_ID" ]; then echo "Failed to create release. API response:" echo "$RESPONSE" exit 1 fi echo "Release created with id $RELEASE_ID." fi curl -s -X POST "$API/releases/$RELEASE_ID/assets" \ -H "Authorization: token $RELEASE_TOKEN" \ -F "attachment=@build/app/outputs/flutter-apk/app-release.apk" echo "Done — $TAG is live at:" echo "https://git.fabledsword.com/bvandeusen/FabledApp/releases/tag/$TAG"