All checks were successful
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 3m11s
Traceability Validation / Check Requirement Traces (push) Successful in 20s
Build & Release / Run Tests (push) Successful in 3m40s
🏗️ Build and Test JellyTau / Build Android APK (push) Successful in 18m36s
Build & Release / Build Linux (push) Successful in 15m56s
Build & Release / Build Android (push) Successful in 18m33s
Build & Release / Create Release (push) Successful in 7s
The release-notes echo lines used unescaped backticks, which the shell ran as command substitution; their output leaked control characters into release_notes.md, so jq failed with 'Invalid string: control characters ... must be escaped' when building the release payload. - Escape the backticks so they are literal markdown. - Remove emoji from the release-notes content (plain ASCII headings). - Handle an already-existing release (HTTP 409) by reusing its id for asset upload instead of failing.
341 lines
12 KiB
YAML
341 lines
12 KiB
YAML
name: Build & Release
|
||
|
||
on:
|
||
push:
|
||
tags:
|
||
- 'v*'
|
||
workflow_dispatch:
|
||
inputs:
|
||
version:
|
||
description: 'Version to build (e.g., v1.0.0)'
|
||
required: false
|
||
|
||
env:
|
||
RUST_BACKTRACE: 1
|
||
CARGO_TERM_COLOR: always
|
||
|
||
jobs:
|
||
test:
|
||
name: Run Tests
|
||
runs-on: linux/amd64
|
||
container:
|
||
image: gitea.tourolle.paris/dtourolle/jellytau-builder:latest
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Cache Rust dependencies
|
||
uses: actions/cache@v3
|
||
with:
|
||
path: |
|
||
~/.cargo/registry
|
||
~/.cargo/git
|
||
src-tauri/target
|
||
key: ${{ runner.os }}-cargo-host-${{ hashFiles('**/Cargo.lock') }}
|
||
restore-keys: |
|
||
${{ runner.os }}-cargo-host-
|
||
|
||
- name: Cache Node dependencies
|
||
uses: actions/cache@v3
|
||
with:
|
||
path: |
|
||
~/.bun/install/cache
|
||
node_modules
|
||
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
|
||
restore-keys: |
|
||
${{ runner.os }}-bun-
|
||
|
||
- name: Install dependencies
|
||
run: bun install
|
||
|
||
- name: Run frontend tests
|
||
run: |
|
||
bunx svelte-kit sync
|
||
bun run test --run
|
||
continue-on-error: false
|
||
|
||
- name: Run Rust tests
|
||
run: bun run test:rust
|
||
continue-on-error: false
|
||
|
||
- name: Check TypeScript
|
||
run: bun run check
|
||
continue-on-error: false
|
||
|
||
build-linux:
|
||
name: Build Linux
|
||
runs-on: linux/amd64
|
||
needs: test
|
||
container:
|
||
image: gitea.tourolle.paris/dtourolle/jellytau-builder:latest
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Cache Rust dependencies
|
||
uses: actions/cache@v3
|
||
with:
|
||
path: |
|
||
~/.cargo/registry
|
||
~/.cargo/git
|
||
src-tauri/target
|
||
key: ${{ runner.os }}-cargo-host-${{ hashFiles('**/Cargo.lock') }}
|
||
restore-keys: |
|
||
${{ runner.os }}-cargo-host-
|
||
|
||
- name: Cache Node dependencies
|
||
uses: actions/cache@v3
|
||
with:
|
||
path: |
|
||
~/.bun/install/cache
|
||
node_modules
|
||
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
|
||
restore-keys: |
|
||
${{ runner.os }}-bun-
|
||
|
||
- name: Install dependencies
|
||
run: bun install
|
||
|
||
- name: Build for Linux
|
||
run: bun run tauri build
|
||
env:
|
||
TAURI_SKIP_UPDATER: true
|
||
|
||
- name: Prepare Linux artifacts
|
||
run: |
|
||
mkdir -p dist/linux
|
||
# Copy AppImage
|
||
if [ -f "src-tauri/target/release/bundle/appimage/jellytau_"*.AppImage ]; then
|
||
cp src-tauri/target/release/bundle/appimage/jellytau_*.AppImage dist/linux/
|
||
fi
|
||
# Copy .deb if built
|
||
if [ -f "src-tauri/target/release/bundle/deb/jellytau_"*.deb ]; then
|
||
cp src-tauri/target/release/bundle/deb/jellytau_*.deb dist/linux/
|
||
fi
|
||
ls -lah dist/linux/
|
||
|
||
- name: Upload Linux build artifact
|
||
uses: actions/upload-artifact@v3
|
||
with:
|
||
name: jellytau-linux
|
||
path: dist/linux/
|
||
retention-days: 30
|
||
|
||
build-android:
|
||
name: Build Android
|
||
runs-on: linux/amd64
|
||
needs: test
|
||
container:
|
||
image: gitea.tourolle.paris/dtourolle/jellytau-builder:latest
|
||
env:
|
||
ANDROID_HOME: /opt/android-sdk
|
||
ANDROID_SDK_ROOT: /opt/android-sdk
|
||
ANDROID_NDK_HOME: /opt/android-sdk/ndk/27.0.11902837
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Cache Rust dependencies
|
||
uses: actions/cache@v3
|
||
with:
|
||
path: |
|
||
~/.cargo/registry
|
||
~/.cargo/git
|
||
src-tauri/target
|
||
key: ${{ runner.os }}-cargo-android-${{ hashFiles('**/Cargo.lock') }}
|
||
restore-keys: |
|
||
${{ runner.os }}-cargo-android-
|
||
|
||
- name: Cache Node dependencies
|
||
uses: actions/cache@v3
|
||
with:
|
||
path: |
|
||
~/.bun/install/cache
|
||
node_modules
|
||
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
|
||
restore-keys: |
|
||
${{ runner.os }}-bun-
|
||
|
||
- name: Install dependencies
|
||
run: bun install
|
||
|
||
- name: Set app version from tag
|
||
run: |
|
||
REF="${GITHUB_REF#refs/tags/v}"
|
||
VERSION="${REF#refs/heads/}"
|
||
# On non-tag runs keep whatever is in tauri.conf.json
|
||
if echo "$GITHUB_REF" | grep -q '^refs/tags/v'; then
|
||
echo "Setting version to $VERSION"
|
||
sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" src-tauri/tauri.conf.json
|
||
fi
|
||
grep '"version"' src-tauri/tauri.conf.json
|
||
|
||
- name: Initialize Android project
|
||
run: bun run tauri android init
|
||
|
||
- name: Sync custom Android sources & gradle config
|
||
run: ./scripts/sync-android-sources.sh
|
||
|
||
- name: Write signing keystore
|
||
run: |
|
||
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > "$RUNNER_TEMP/jellytau-release.jks"
|
||
cat > src-tauri/gen/android/keystore.properties <<EOF
|
||
storeFile=$RUNNER_TEMP/jellytau-release.jks
|
||
storePassword=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
||
keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}
|
||
keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}
|
||
EOF
|
||
|
||
- name: Build signed Android APK
|
||
run: bun run tauri android build --apk true --target aarch64
|
||
|
||
- name: Collect & verify signed APK
|
||
run: |
|
||
mkdir -p dist/android
|
||
APK=$(find src-tauri/gen/android/app/build/outputs/apk -name '*-release.apk' | head -1)
|
||
if [ -z "$APK" ]; then echo "❌ No release APK produced"; exit 1; fi
|
||
cp "$APK" dist/android/jellytau-release.apk
|
||
APKSIGNER=$(find "$ANDROID_SDK_ROOT/build-tools" -name apksigner | sort -V | tail -1)
|
||
echo "🔏 Verifying signature with $APKSIGNER"
|
||
"$APKSIGNER" verify --print-certs dist/android/jellytau-release.apk
|
||
ls -lah dist/android/
|
||
|
||
- name: Upload Android build artifact
|
||
uses: actions/upload-artifact@v3
|
||
with:
|
||
name: jellytau-android
|
||
path: dist/android/
|
||
retention-days: 30
|
||
|
||
create-release:
|
||
name: Create Release
|
||
runs-on: linux/amd64
|
||
needs: [build-linux, build-android]
|
||
if: startsWith(github.ref, 'refs/tags/v')
|
||
container:
|
||
image: gitea.tourolle.paris/dtourolle/jellytau-builder:latest
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Get version from tag
|
||
id: tag_name
|
||
run: |
|
||
echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||
echo "RELEASE_NAME=JellyTau ${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||
|
||
- name: Download Linux artifacts
|
||
uses: actions/download-artifact@v3
|
||
with:
|
||
name: jellytau-linux
|
||
path: artifacts/linux/
|
||
|
||
- name: Download Android artifacts
|
||
uses: actions/download-artifact@v3
|
||
with:
|
||
name: jellytau-android
|
||
path: artifacts/android/
|
||
|
||
- name: Prepare release notes
|
||
id: release_notes
|
||
run: |
|
||
VERSION="${{ steps.tag_name.outputs.VERSION }}"
|
||
echo "## JellyTau $VERSION Release" > release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "### Downloads" >> release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "#### Linux" >> release_notes.md
|
||
echo "- **AppImage** - Run directly on most Linux distributions" >> release_notes.md
|
||
echo "- **DEB** - Install via \`sudo dpkg -i jellytau_*.deb\` (Ubuntu/Debian)" >> release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "#### Android" >> release_notes.md
|
||
echo "- **APK** - Install via \`adb install jellytau-release.apk\` or sideload via file manager" >> release_notes.md
|
||
echo "- **AAB** - Upload to Google Play Console or testing platforms" >> release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "### What's New" >> release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "See [CHANGELOG.md](CHANGELOG.md) for detailed changes." >> release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "### Installation" >> release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "#### Linux (AppImage)" >> release_notes.md
|
||
echo "\`\`\`bash" >> release_notes.md
|
||
echo "chmod +x jellytau_*.AppImage" >> release_notes.md
|
||
echo "./jellytau_*.AppImage" >> release_notes.md
|
||
echo "\`\`\`" >> release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "#### Linux (DEB)" >> release_notes.md
|
||
echo "\`\`\`bash" >> release_notes.md
|
||
echo "sudo dpkg -i jellytau_*.deb" >> release_notes.md
|
||
echo "jellytau" >> release_notes.md
|
||
echo "\`\`\`" >> release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "#### Android" >> release_notes.md
|
||
echo "- Sideload: Download APK and install via file manager or ADB" >> release_notes.md
|
||
echo "- Play Store: Coming soon" >> release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "### Known Issues" >> release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "See [GitHub Issues](../../issues) for reported bugs." >> release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "### Requirements" >> release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "**Linux:**" >> release_notes.md
|
||
echo "- 64-bit Linux system" >> release_notes.md
|
||
echo "- GLIBC 2.29+" >> release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "**Android:**" >> release_notes.md
|
||
echo "- Android 8.0 or higher" >> release_notes.md
|
||
echo "- 50MB free storage" >> release_notes.md
|
||
echo "" >> release_notes.md
|
||
echo "---" >> release_notes.md
|
||
echo "Built with Tauri, SvelteKit, and Rust" >> release_notes.md
|
||
|
||
- name: Publish Gitea release & upload assets
|
||
env:
|
||
# GITEA_TOKEN (a PAT) is preferred; falls back to the auto-provided token.
|
||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||
AUTO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
run: |
|
||
set -e
|
||
command -v jq >/dev/null || { echo "❌ jq is required on the runner"; exit 1; }
|
||
VERSION="${{ steps.tag_name.outputs.VERSION }}"
|
||
API="${GITHUB_SERVER_URL}/api/v1"
|
||
REPO="${GITHUB_REPOSITORY}"
|
||
TOKEN="${GITEA_TOKEN:-$AUTO_TOKEN}"
|
||
case "$VERSION" in *rc*|*beta*|*alpha*) PRE=true;; *) PRE=false;; esac
|
||
|
||
PAYLOAD=$(jq -n \
|
||
--arg tag "$VERSION" \
|
||
--arg name "JellyTau $VERSION" \
|
||
--rawfile body release_notes.md \
|
||
--argjson pre "$PRE" \
|
||
'{tag_name:$tag, name:$name, body:$body, draft:false, prerelease:$pre}')
|
||
|
||
echo "📦 Creating release $VERSION on $REPO"
|
||
# -f drops on HTTP error; capture status so an existing release (409) is handled gracefully.
|
||
HTTP=$(curl -sS -o resp.json -w '%{http_code}' -X POST "$API/repos/$REPO/releases" \
|
||
-H "Authorization: token $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$PAYLOAD")
|
||
if [ "$HTTP" = "201" ]; then
|
||
RELEASE_ID=$(jq -r '.id' resp.json)
|
||
elif [ "$HTTP" = "409" ]; then
|
||
echo "ℹ️ Release $VERSION already exists; fetching its id to upload assets"
|
||
RELEASE_ID=$(curl -fsS "$API/repos/$REPO/releases/tags/$VERSION" \
|
||
-H "Authorization: token $TOKEN" | jq -r '.id')
|
||
else
|
||
echo "❌ Failed to create release (HTTP $HTTP):"; cat resp.json; exit 1
|
||
fi
|
||
echo "Release id=$RELEASE_ID"
|
||
|
||
for f in artifacts/android/* artifacts/linux/*; do
|
||
[ -f "$f" ] || continue
|
||
echo "⬆️ Uploading $(basename "$f")"
|
||
curl -fsS -X POST \
|
||
"$API/repos/$REPO/releases/$RELEASE_ID/assets?name=$(basename "$f")" \
|
||
-H "Authorization: token $TOKEN" \
|
||
-F "attachment=@$f" >/dev/null
|
||
done
|
||
echo "✅ Release $VERSION published with assets"
|