Skip to content

Commit 4ac364a

Browse files
wgqqqqqcursoragent
andcommitted
ci: add Release Please, CI checks, nightly builds and unify version management
- Unify version across all 11 crates using Cargo workspace.package.version as the single source of truth (all crates now use version.workspace = true) - Remove version field from tauri.conf.json (Tauri 2 falls back to Cargo.toml) - Normalize package.json version to standard semver "0.1.0" - Add CI workflow (ci.yml): rust-lint, rust-test, rust-build-check, frontend-build with concurrency control and cancel-in-progress - Add Release Please workflow + config for automated versioning and changelog generation based on Conventional Commits - Refactor desktop-package.yml to trigger on release:published event instead of manually detecting version changes in tauri.conf.json - Add nightly build workflow: scheduled weekday builds with pre-release publishing Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 6e7ff2a commit 4ac364a

File tree

19 files changed

+413
-50
lines changed

19 files changed

+413
-50
lines changed

.github/workflows/ci.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
push:
7+
branches: [main]
8+
9+
# Cancel previous runs on same branch/PR
10+
concurrency:
11+
group: ci-${{ github.ref }}
12+
cancel-in-progress: true
13+
14+
permissions:
15+
contents: read
16+
17+
jobs:
18+
# ── Rust: build check ─────────────────────────────────────────────
19+
rust-build-check:
20+
name: Rust Build Check
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- uses: dtolnay/rust-toolchain@stable
26+
27+
- uses: swatinem/rust-cache@v2
28+
with:
29+
shared-key: "ci-check"
30+
31+
- name: Check compilation
32+
run: cargo check --all-targets
33+
34+
# ── Frontend: build ────────────────────────────────────────────────
35+
frontend-build:
36+
name: Frontend Build
37+
runs-on: ubuntu-latest
38+
steps:
39+
- uses: actions/checkout@v4
40+
41+
- uses: pnpm/action-setup@v4
42+
43+
- uses: actions/setup-node@v4
44+
with:
45+
node-version: 20
46+
cache: pnpm
47+
48+
- name: Install dependencies
49+
run: pnpm install --frozen-lockfile
50+
51+
- name: Build web UI
52+
run: pnpm build:web
Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,74 @@
11
name: Desktop Package
22

33
on:
4+
# Triggered automatically when Release Please publishes a release
5+
release:
6+
types: [published]
7+
# Manual trigger for ad-hoc builds
48
workflow_dispatch:
5-
push:
6-
tags:
7-
- "v*"
9+
inputs:
10+
tag_name:
11+
description: "Tag name to build (e.g. v0.2.0). Leave empty to build from HEAD."
12+
required: false
13+
type: string
814

915
permissions:
1016
contents: write
1117

1218
jobs:
19+
# ── Resolve version info ───────────────────────────────────────────
20+
prepare:
21+
name: Prepare
22+
runs-on: ubuntu-latest
23+
outputs:
24+
version: ${{ steps.meta.outputs.version }}
25+
release_tag: ${{ steps.meta.outputs.release_tag }}
26+
upload_to_release: ${{ steps.meta.outputs.upload_to_release }}
27+
steps:
28+
- uses: actions/checkout@v4
29+
30+
- name: Resolve version metadata
31+
id: meta
32+
shell: bash
33+
run: |
34+
set -euo pipefail
35+
36+
if [[ "${{ github.event_name }}" == "release" ]]; then
37+
TAG="${{ github.event.release.tag_name }}"
38+
VERSION="${TAG#v}"
39+
UPLOAD="true"
40+
elif [[ -n "${{ inputs.tag_name }}" ]]; then
41+
TAG="${{ inputs.tag_name }}"
42+
VERSION="${TAG#v}"
43+
UPLOAD="false"
44+
else
45+
VERSION="$(jq -r '.version' package.json)"
46+
TAG="v${VERSION}"
47+
UPLOAD="false"
48+
fi
49+
50+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
51+
echo "release_tag=$TAG" >> "$GITHUB_OUTPUT"
52+
echo "upload_to_release=$UPLOAD" >> "$GITHUB_OUTPUT"
53+
54+
# ── Build per platform ─────────────────────────────────────────────
1355
package:
1456
name: Package (${{ matrix.platform.name }})
1557
runs-on: ${{ matrix.platform.os }}
58+
needs: prepare
1659

1760
strategy:
1861
fail-fast: false
1962
matrix:
2063
platform:
21-
- os: macos-15-intel
22-
name: macos-x64
23-
target: x86_64-apple-darwin
24-
build_command: pnpm desktop:build:x86_64
2564
- os: macos-15
2665
name: macos-arm64
2766
target: aarch64-apple-darwin
2867
build_command: pnpm build:web && cd src/apps/desktop && pnpm tauri build --target aarch64-apple-darwin --bundles dmg
68+
- os: macos-15-intel
69+
name: macos-x64
70+
target: x86_64-apple-darwin
71+
build_command: pnpm desktop:build:x86_64
2972
- os: windows-latest
3073
name: windows-x64
3174
target: x86_64-pc-windows-msvc
@@ -34,6 +77,8 @@ jobs:
3477
steps:
3578
- name: Checkout
3679
uses: actions/checkout@v4
80+
with:
81+
ref: ${{ needs.prepare.outputs.release_tag }}
3782

3883
- name: Setup pnpm
3984
uses: pnpm/action-setup@v4
@@ -52,8 +97,7 @@ jobs:
5297
- name: Cache Rust build
5398
uses: swatinem/rust-cache@v2
5499
with:
55-
workspaces: |
56-
. -> target
100+
shared-key: "package-${{ matrix.platform.name }}"
57101

58102
- name: Install dependencies
59103
run: pnpm install --frozen-lockfile
@@ -64,24 +108,25 @@ jobs:
64108
- name: Upload bundles
65109
uses: actions/upload-artifact@v4
66110
with:
67-
name: bitfun-${{ matrix.platform.name }}-bundle
111+
name: bitfun-${{ needs.prepare.outputs.release_tag }}-${{ matrix.platform.name }}-bundle
68112
if-no-files-found: error
69113
path: |
70114
target/*/release/bundle
71115
target/release/bundle
72116
src/apps/desktop/target/release/bundle
73117
74-
release:
75-
name: Create GitHub Release
76-
if: startsWith(github.ref, 'refs/tags/v')
77-
needs: package
118+
# ── Upload assets to GitHub Release ────────────────────────────────
119+
upload-release-assets:
120+
name: Upload Release Assets
121+
needs: [prepare, package]
122+
if: needs.prepare.outputs.upload_to_release == 'true'
78123
runs-on: ubuntu-latest
79124

80125
steps:
81126
- name: Download bundled artifacts
82127
uses: actions/download-artifact@v4
83128
with:
84-
pattern: bitfun-*-bundle
129+
pattern: bitfun-${{ needs.prepare.outputs.release_tag }}-*-bundle
85130
path: release-assets
86131
merge-multiple: true
87132

@@ -90,14 +135,11 @@ jobs:
90135
echo "Release assets:"
91136
find release-assets -type f | sort
92137
93-
- name: Publish release
138+
- name: Upload to release
94139
uses: softprops/action-gh-release@v2
95140
with:
96-
tag_name: ${{ github.ref_name }}
97-
name: ${{ github.ref_name }}
98-
generate_release_notes: true
141+
tag_name: ${{ needs.prepare.outputs.release_tag }}
99142
files: |
100143
release-assets/**/*.dmg
101144
release-assets/**/*setup.exe
102-
overwrite_files: true
103145
fail_on_unmatched_files: true

.github/workflows/nightly.yml

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
name: Nightly Build
2+
3+
on:
4+
schedule:
5+
# Weekdays at 02:00 UTC
6+
- cron: "0 2 * * 1-5"
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: write
11+
12+
concurrency:
13+
group: nightly
14+
cancel-in-progress: true
15+
16+
env:
17+
NIGHTLY_TAG: nightly
18+
19+
jobs:
20+
# ── Check if there are new commits since last nightly ──────────────
21+
check-changes:
22+
name: Check for Changes
23+
runs-on: ubuntu-latest
24+
outputs:
25+
should_build: ${{ steps.check.outputs.should_build }}
26+
nightly_version: ${{ steps.check.outputs.nightly_version }}
27+
steps:
28+
- uses: actions/checkout@v4
29+
with:
30+
fetch-depth: 0
31+
32+
- name: Check for recent changes
33+
id: check
34+
shell: bash
35+
run: |
36+
set -euo pipefail
37+
38+
BASE_VERSION="$(jq -r '.version' package.json)"
39+
DATE_SUFFIX="$(date -u '+%Y%m%d')"
40+
SHORT_SHA="$(git rev-parse --short HEAD)"
41+
NIGHTLY_VERSION="${BASE_VERSION}-nightly.${DATE_SUFFIX}+${SHORT_SHA}"
42+
43+
echo "nightly_version=$NIGHTLY_VERSION" >> "$GITHUB_OUTPUT"
44+
45+
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
46+
echo "should_build=true" >> "$GITHUB_OUTPUT"
47+
exit 0
48+
fi
49+
50+
# Check if any commits landed in the last 25 hours
51+
LAST_COMMIT_TIME="$(git log -1 --format='%ct')"
52+
NOW="$(date -u '+%s')"
53+
HOURS_AGO=$(( (NOW - LAST_COMMIT_TIME) / 3600 ))
54+
55+
if [[ "$HOURS_AGO" -lt 25 ]]; then
56+
echo "should_build=true" >> "$GITHUB_OUTPUT"
57+
else
58+
echo "No new commits in the last 25 hours, skipping nightly build."
59+
echo "should_build=false" >> "$GITHUB_OUTPUT"
60+
fi
61+
62+
# ── Patch version for nightly ──────────────────────────────────────
63+
package:
64+
name: Package (${{ matrix.platform.name }})
65+
runs-on: ${{ matrix.platform.os }}
66+
needs: check-changes
67+
if: needs.check-changes.outputs.should_build == 'true'
68+
69+
strategy:
70+
fail-fast: false
71+
matrix:
72+
platform:
73+
- os: macos-15
74+
name: macos-arm64
75+
target: aarch64-apple-darwin
76+
build_command: pnpm build:web && cd src/apps/desktop && pnpm tauri build --target aarch64-apple-darwin --bundles dmg
77+
- os: macos-15-intel
78+
name: macos-x64
79+
target: x86_64-apple-darwin
80+
build_command: pnpm desktop:build:x86_64
81+
- os: windows-latest
82+
name: windows-x64
83+
target: x86_64-pc-windows-msvc
84+
build_command: pnpm desktop:build:nsis
85+
86+
steps:
87+
- uses: actions/checkout@v4
88+
89+
- name: Setup pnpm
90+
uses: pnpm/action-setup@v4
91+
92+
- name: Setup Node.js
93+
uses: actions/setup-node@v4
94+
with:
95+
node-version: 20
96+
cache: pnpm
97+
98+
- name: Setup Rust toolchain
99+
uses: dtolnay/rust-toolchain@stable
100+
with:
101+
targets: ${{ matrix.platform.target }}
102+
103+
- name: Cache Rust build
104+
uses: swatinem/rust-cache@v2
105+
with:
106+
shared-key: "nightly-${{ matrix.platform.name }}"
107+
108+
- name: Install dependencies
109+
run: pnpm install --frozen-lockfile
110+
111+
- name: Patch nightly version
112+
shell: bash
113+
env:
114+
NIGHTLY_VERSION: ${{ needs.check-changes.outputs.nightly_version }}
115+
run: |
116+
set -euo pipefail
117+
118+
echo "Patching version to $NIGHTLY_VERSION"
119+
120+
# Patch package.json
121+
node -e "
122+
const fs = require('fs');
123+
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
124+
pkg.version = process.env.NIGHTLY_VERSION.split('+')[0];
125+
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
126+
"
127+
128+
# Patch Cargo workspace version (semver: nightly suffix uses hyphen)
129+
# Cargo.toml only accepts: MAJOR.MINOR.PATCH or MAJOR.MINOR.PATCH-PRE
130+
CARGO_VERSION="$(echo "$NIGHTLY_VERSION" | sed 's/+.*//')"
131+
sed -i.bak "s/^version = \".*\" # x-release-please-version/version = \"${CARGO_VERSION}\" # x-release-please-version/" Cargo.toml
132+
rm -f Cargo.toml.bak
133+
134+
echo "package.json version: $(jq -r '.version' package.json)"
135+
echo "Cargo.toml version: $(grep 'x-release-please-version' Cargo.toml)"
136+
137+
- name: Build desktop app
138+
run: ${{ matrix.platform.build_command }}
139+
140+
- name: Upload bundles
141+
uses: actions/upload-artifact@v4
142+
with:
143+
name: bitfun-nightly-${{ matrix.platform.name }}-bundle
144+
if-no-files-found: error
145+
retention-days: 7
146+
path: |
147+
target/*/release/bundle
148+
target/release/bundle
149+
src/apps/desktop/target/release/bundle
150+
151+
# ── Publish nightly pre-release ────────────────────────────────────
152+
publish-nightly:
153+
name: Publish Nightly
154+
needs: [check-changes, package]
155+
if: needs.check-changes.outputs.should_build == 'true'
156+
runs-on: ubuntu-latest
157+
158+
steps:
159+
- uses: actions/checkout@v4
160+
161+
- name: Download bundled artifacts
162+
uses: actions/download-artifact@v4
163+
with:
164+
pattern: bitfun-nightly-*-bundle
165+
path: release-assets
166+
merge-multiple: true
167+
168+
- name: List release assets
169+
run: |
170+
echo "Nightly assets:"
171+
find release-assets -type f | sort
172+
173+
- name: Delete previous nightly release
174+
env:
175+
GH_TOKEN: ${{ github.token }}
176+
run: |
177+
gh release delete "${{ env.NIGHTLY_TAG }}" --yes --cleanup-tag 2>/dev/null || true
178+
179+
- name: Create nightly release
180+
uses: softprops/action-gh-release@v2
181+
with:
182+
tag_name: ${{ env.NIGHTLY_TAG }}
183+
name: "Nightly Build (${{ needs.check-changes.outputs.nightly_version }})"
184+
body: |
185+
Automated nightly build from `main` branch.
186+
187+
**Version**: `${{ needs.check-changes.outputs.nightly_version }}`
188+
**Commit**: ${{ github.sha }}
189+
**Date**: ${{ github.event.head_commit.timestamp || github.event.repository.updated_at }}
190+
191+
> **Warning**: Nightly builds are untested and may be unstable.
192+
prerelease: true
193+
files: |
194+
release-assets/**/*.dmg
195+
release-assets/**/*setup.exe

0 commit comments

Comments
 (0)