fix(ci): add prepare job, auto-version, fix Windows build issues

- Add prepare job: computes version (4.12.{run_number}), creates/updates
  the Gitea release once — eliminates the race condition where build-windows
  and build-linux both tried to create the same release simultaneously.
- Auto-increment version: both build jobs patch tauri.conf.json with
  4.12.{run_number} before building, so every CI run produces a strictly
  increasing semver and the Tauri updater fires correctly.
- Fix double -- in Windows build command: was 'build -- --bundles nsis'
  which passed --bundles as cargo args (silently ignored), causing all
  bundle targets to build. Now 'build --bundles nsis' (single --).
- Add setup-node to Windows build: pins Node.js to .node-version like
  the Linux job already does.
- update-manifest: uses version/release_id from prepare outputs instead
  of re-fetching and parsing the release name.
- Fix window title: was "Cinny", now "Lotus Chat".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 16:56:18 -04:00
parent dffe5fb05a
commit ed718704ee
2 changed files with 61 additions and 40 deletions
+60 -39
View File
@@ -10,15 +10,57 @@ env:
REPO: LotusGuild/cinny-desktop
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.ver.outputs.version }}
release_id: ${{ steps.release.outputs.release_id }}
steps:
- name: Compute version
id: ver
run: echo "version=4.12.${{ github.run_number }}" >> $GITHUB_OUTPUT
- name: Create or update release
id: release
env:
TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
VERSION="4.12.${{ github.run_number }}"
EXISTING=$(curl -sf "$GITEA_URL/api/v1/repos/$REPO/releases/tags/latest" \
-H "Authorization: token $TOKEN" 2>/dev/null || true)
RELEASE_ID=$(echo "$EXISTING" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('id',''))" 2>/dev/null || true)
if [ -n "$RELEASE_ID" ] && [ "$RELEASE_ID" != "None" ] && [ "$RELEASE_ID" != "" ]; then
curl -sf -X PATCH "$GITEA_URL/api/v1/repos/$REPO/releases/$RELEASE_ID" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"name\":\"Lotus Chat $VERSION\",\"body\":\"Built from ${{ github.sha }}\"}" > /dev/null
else
RELEASE_ID=$(curl -sf -X POST "$GITEA_URL/api/v1/repos/$REPO/releases" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"tag_name\":\"latest\",\"name\":\"Lotus Chat $VERSION\",\"prerelease\":true,\"body\":\"Built from ${{ github.sha }}\"}" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
fi
echo "release_id=$RELEASE_ID" >> $GITHUB_OUTPUT
build-windows:
needs: prepare
runs-on: windows
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .node-version
- name: Checkout submodules (shallow)
shell: powershell
run: git submodule update --init --depth=1
- name: Patch version
shell: powershell
run: python3 -c "import json; d=json.load(open('src-tauri/tauri.conf.json')); d['version']='${{ needs.prepare.outputs.version }}'; open('src-tauri/tauri.conf.json','w').write(json.dumps(d,indent=2))"
- name: Install frontend deps
shell: powershell
run: cd cinny; npm ci
@@ -33,25 +75,18 @@ jobs:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ''
NODE_OPTIONS: '--max_old_space_size=4096'
run: npm run tauri -- build -- --bundles nsis
run: npm run tauri -- build --bundles nsis
- name: Upload to release
shell: powershell
env:
TOKEN: ${{ secrets.RELEASE_TOKEN }}
RELEASE_ID: ${{ needs.prepare.outputs.release_id }}
VERSION: ${{ needs.prepare.outputs.version }}
run: |
$VERSION = (Get-Content "src-tauri\tauri.conf.json" | ConvertFrom-Json).version
Write-Host "Version: $VERSION"
$release = Invoke-RestMethod -Uri "$env:GITEA_URL/api/v1/repos/$env:REPO/releases/tags/latest" `
-Headers @{ Authorization = "token $env:TOKEN" } -ErrorAction SilentlyContinue
if (-not $release) {
$release = Invoke-RestMethod -Uri "$env:GITEA_URL/api/v1/repos/$env:REPO/releases" `
-Method Post `
-Headers @{ Authorization = "token $env:TOKEN"; "Content-Type" = "application/json" } `
-Body "{`"tag_name`":`"latest`",`"name`":`"Lotus Chat $VERSION`",`"prerelease`":true,`"body`":`"Built from ${{ github.sha }}`"}"
}
$releaseId = $release.id
$releaseId = $env:RELEASE_ID
$VERSION = $env:VERSION
Write-Host "Version: $VERSION Release: $releaseId"
$nsis = "src-tauri\target\release\bundle\nsis"
$files = @(
@@ -75,6 +110,7 @@ jobs:
}
build-linux:
needs: prepare
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -104,6 +140,9 @@ jobs:
with:
workspaces: src-tauri
- name: Patch version
run: python3 -c "import json; d=json.load(open('src-tauri/tauri.conf.json')); d['version']='${{ needs.prepare.outputs.version }}'; open('src-tauri/tauri.conf.json','w').write(json.dumps(d,indent=2))"
- name: Install frontend deps
run: cd cinny && npm ci
@@ -126,24 +165,12 @@ jobs:
- name: Upload to release
env:
TOKEN: ${{ secrets.RELEASE_TOKEN }}
RELEASE_ID: ${{ needs.prepare.outputs.release_id }}
VERSION: ${{ needs.prepare.outputs.version }}
run: |
VERSION=$(python3 -c "import json; print(json.load(open('src-tauri/tauri.conf.json'))['version'])")
echo "Version: $VERSION"
APPIMAGE_DIR="src-tauri/target/release/bundle/appimage"
DEB_DIR="src-tauri/target/release/bundle/deb"
RELEASE=$(curl -sf "$GITEA_URL/api/v1/repos/$REPO/releases/tags/latest" \
-H "Authorization: token $TOKEN" 2>/dev/null || true)
RELEASE_ID=$(echo "$RELEASE" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "None" ]; then
RELEASE_ID=$(curl -sf -X POST "$GITEA_URL/api/v1/repos/$REPO/releases" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"tag_name\":\"latest\",\"name\":\"Lotus Chat $VERSION\",\"prerelease\":true,\"body\":\"Built from ${{ github.sha }}\"}" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
fi
upload() {
local name="$1" path="$2"
local existing_id
@@ -162,31 +189,25 @@ jobs:
--data-binary @"$path"
}
upload "LotusChat-x86_64.AppImage" "$APPIMAGE_DIR/Lotus Chat_${VERSION}_amd64.AppImage"
upload "LotusChat-x86_64.AppImage.tar.gz" "$APPIMAGE_DIR/Lotus Chat_${VERSION}_amd64.AppImage.tar.gz"
upload "LotusChat-x86_64.AppImage" "$APPIMAGE_DIR/Lotus Chat_${VERSION}_amd64.AppImage"
upload "LotusChat-x86_64.AppImage.tar.gz" "$APPIMAGE_DIR/Lotus Chat_${VERSION}_amd64.AppImage.tar.gz"
upload "LotusChat-x86_64.AppImage.tar.gz.sig" "$APPIMAGE_DIR/Lotus Chat_${VERSION}_amd64.AppImage.tar.gz.sig"
upload "LotusChat-x86_64.deb" "$DEB_DIR/Lotus Chat_${VERSION}_amd64.deb"
upload "LotusChat-x86_64.deb" "$DEB_DIR/Lotus Chat_${VERSION}_amd64.deb"
update-manifest:
needs: [build-windows, build-linux]
needs: [prepare, build-windows, build-linux]
runs-on: ubuntu-latest
env:
GITEA_URL: https://code.lotusguild.org
REPO: LotusGuild/cinny-desktop
steps:
- name: Generate and upload release.json
env:
TOKEN: ${{ secrets.RELEASE_TOKEN }}
RELEASE_ID: ${{ needs.prepare.outputs.release_id }}
VERSION: ${{ needs.prepare.outputs.version }}
run: |
BASE="$GITEA_URL/LotusGuild/cinny-desktop/releases/download/latest"
WIN_SIG=$(curl -sf "$BASE/LotusChat-x86_64-setup.nsis.zip.sig")
LIN_SIG=$(curl -sf "$BASE/LotusChat-x86_64.AppImage.tar.gz.sig")
RELEASE=$(curl -sf "$GITEA_URL/api/v1/repos/$REPO/releases/tags/latest" \
-H "Authorization: token $TOKEN")
RELEASE_ID=$(echo "$RELEASE" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
VERSION=$(echo "$RELEASE" | python3 -c "import sys,json; print(json.load(sys.stdin)['name'].split()[-1])")
DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)
python3 -c "import json,sys; v,d,wu,ws,lu,ls=sys.argv[1:]; print(json.dumps({'version':v,'notes':'Latest Lotus Chat release','pub_date':d,'platforms':{'windows-x86_64':{'url':wu,'signature':ws},'linux-x86_64':{'url':lu,'signature':ls}}},indent=2))" \
+1 -1
View File
@@ -27,7 +27,7 @@ pub fn run() {
let app_handle = app.handle().clone();
let window = WebviewWindowBuilder::new(app, "main".to_string(), window_url)
.title("Cinny")
.title("Lotus Chat")
.disable_drag_drop_handler()
.on_new_window(move |url, _features| {
let _ = app_handle.opener().open_url(url.as_str(), None::<&str>);