1+ name : Manually Triggered Desktop Release
2+
3+ permissions :
4+ contents : write
5+ actions : read
6+
7+ concurrency :
8+ group : desktop-release-${{ github.ref }}
9+ cancel-in-progress : true
10+
11+ on :
12+ workflow_dispatch :
13+ inputs :
14+ version-bump :
15+ description : ' The type of version bump (major, minor, or patch)'
16+ required : true
17+ default : ' patch'
18+ type : choice
19+ options :
20+ - patch
21+ - minor
22+ - major
23+
24+ jobs :
25+ version :
26+ runs-on : ubuntu-latest
27+ outputs :
28+ new_version : ${{ steps.bump.outputs.new_version }}
29+ changelog : ${{ steps.changelog.outputs.clean_changelog }}
30+ steps :
31+ - name : Checkout repository
32+ uses : actions/checkout@v4
33+ with :
34+ fetch-depth : 0
35+ token : ${{ secrets.GITHUB_TOKEN }}
36+
37+ - name : Configure Git
38+ run : |
39+ git config user.name "github-actions[bot]"
40+ git config user.email "github-actions[bot]@users.noreply.github.com"
41+
42+ - name : Compute New Version
43+ id : bump
44+ run : |
45+ set -euo pipefail
46+
47+ # Fetch the latest tag from the repository
48+ LATEST_TAG=$(git tag --sort=-v:refname | head -n 1)
49+ if [[ -z "$LATEST_TAG" ]]; then
50+ LATEST_TAG="v0.0.0"
51+ fi
52+
53+ # Parse the latest tag to get major, minor, and patch numbers
54+ if [[ "$LATEST_TAG" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+) ]]; then
55+ MAJOR=${BASH_REMATCH[1]}
56+ MINOR=${BASH_REMATCH[2]}
57+ PATCH=${BASH_REMATCH[3]}
58+ else
59+ echo "Could not parse latest tag: $LATEST_TAG. Starting from v0.0.0."
60+ MAJOR=0; MINOR=0; PATCH=0
61+ fi
62+
63+ # Increment the version based on the manual input
64+ BUMP_TYPE="${{ github.event.inputs.version-bump }}"
65+ if [ "$BUMP_TYPE" == "major" ]; then
66+ MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0
67+ elif [ "$BUMP_TYPE" == "minor" ]; then
68+ MINOR=$((MINOR + 1)); PATCH=0
69+ else
70+ PATCH=$((PATCH + 1))
71+ fi
72+
73+ NEW_VERSION="v$MAJOR.$MINOR.$PATCH"
74+ VERSION_NO_V="$MAJOR.$MINOR.$PATCH"
75+
76+ echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
77+ echo "version_no_v=$VERSION_NO_V" >> "$GITHUB_OUTPUT"
78+ echo "New version will be: $NEW_VERSION"
79+
80+ - name : Update Version Files
81+ run : |
82+ VERSION_NO_V="${{ steps.bump.outputs.version_no_v }}"
83+
84+ # Update package.json
85+ jq --arg ver "$VERSION_NO_V" '.version = $ver' package.json > package.json.tmp
86+ mv package.json.tmp package.json
87+
88+ # Update src-tauri/tauri.conf.json
89+ jq --arg ver "$VERSION_NO_V" '.version = $ver' src-tauri/tauri.conf.json > src-tauri/tauri.conf.json.tmp
90+ mv src-tauri/tauri.conf.json.tmp src-tauri/tauri.conf.json
91+
92+ # Update src-tauri/Cargo.toml
93+ sed -i "s/^version = \".*\"/version = \"$VERSION_NO_V\"/" src-tauri/Cargo.toml
94+
95+ echo "Updated version files to $VERSION_NO_V"
96+
97+ - name : Generate Changelog
98+ id : changelog
99+ uses : TriPSs/conventional-changelog-action@v6
100+ with :
101+ github-token : ${{ secrets.GITHUB_TOKEN }}
102+ skip-on-empty : ' false'
103+ skip-commit : ' true'
104+ skip-version-file : ' true'
105+ skip-git-pull : ' true'
106+ skip-tag : ' true'
107+ git-push : ' false'
108+ output-file : ' false'
109+ release-count : 0
110+ tag-prefix : ' v'
111+
112+ - name : Commit Version Bump
113+ run : |
114+ NEW_VERSION="${{ steps.bump.outputs.new_version }}"
115+
116+ git add package.json src-tauri/tauri.conf.json src-tauri/Cargo.toml
117+ git commit -m "chore: bump version to $NEW_VERSION"
118+ git tag "$NEW_VERSION"
119+ git push origin HEAD:${{ github.ref_name }}
120+ git push origin "$NEW_VERSION"
121+
122+ build-tauri :
123+ runs-on : ${{ matrix.os }}
124+ needs : version
125+ strategy :
126+ fail-fast : false
127+ matrix :
128+ os : [ubuntu-latest, windows-2022, macos-latest]
129+
130+ steps :
131+ - name : Checkout repository
132+ uses : actions/checkout@v4
133+ with :
134+ ref : ${{ github.ref_name }}
135+ fetch-depth : 0
136+
137+ - name : Pull latest changes
138+ run : git pull origin ${{ github.ref_name }}
139+
140+ - name : Setup Node.js
141+ uses : actions/setup-node@v4
142+ with :
143+ node-version : 22
144+
145+ - name : Cache Node.js Dependencies
146+ uses : actions/cache@v4
147+ with :
148+ path : ~/.npm
149+ key : ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
150+ restore-keys : ${{ runner.os }}-node-
151+
152+ - name : Install Dependencies
153+ run : npm ci
154+ shell : bash
155+
156+ - name : Setup Rust (stable)
157+ uses : dtolnay/rust-toolchain@stable
158+
159+ - name : Install Linux Dependencies (Ubuntu)
160+ if : matrix.os == 'ubuntu-latest'
161+ run : |
162+ sudo apt update
163+ sudo apt install -y libwebkit2gtk-4.1-dev \
164+ build-essential \
165+ curl \
166+ wget \
167+ file \
168+ libxdo-dev \
169+ libssl-dev \
170+ libayatana-appindicator3-dev \
171+ librsvg2-dev
172+ shell : bash
173+
174+ - name : Install macOS Dependencies
175+ if : matrix.os == 'macos-latest'
176+ run : |
177+ brew update
178+ brew install pkg-config
179+ shell : bash
180+
181+ - name : Install Windows Dependencies
182+ if : matrix.os == 'windows-2022'
183+ shell : powershell
184+ run : |
185+ choco install -y wixtoolset nsis webview2-runtime
186+
187+ - name : Cache Rust Dependencies
188+ uses : Swatinem/rust-cache@v2
189+ with :
190+ workspaces : ' ./src-tauri'
191+
192+ - name : Build Tauri App
193+ run : npm run tauri build
194+ shell : bash
195+
196+ # TODO: Add code signing steps here once certificates are obtained
197+ # - Windows: Sign .msi and .exe files with Authenticode via SignPath
198+ # - macOS: Sign .app bundles and .dmg with Apple Developer ID
199+ # - Linux: Sign .deb and .AppImage with GPG
200+ # Reference: Issue #631
201+
202+ - name : Upload Tauri Build Artifacts
203+ uses : actions/upload-artifact@v4
204+ with :
205+ name : Tauri Build Artifacts (${{ matrix.os }})
206+ path : |
207+ src-tauri/target/release/bundle
208+
209+ create-release :
210+ runs-on : ubuntu-latest
211+ needs : [version, build-tauri]
212+ steps :
213+ - name : Checkout repository
214+ uses : actions/checkout@v4
215+ with :
216+ fetch-depth : 0
217+ token : ${{ secrets.GITHUB_TOKEN }}
218+ ref : ${{ github.ref_name }}
219+
220+ - name : Configure Git
221+ run : |
222+ git config user.name "github-actions[bot]"
223+ git config user.email "github-actions[bot]@users.noreply.github.com"
224+
225+ - name : Update Repository Changelog
226+ run : |
227+ set -euo pipefail
228+ CHANGELOG_FILE="CHANGELOG.md"
229+ TEMP_CHANGELOG="$(mktemp)"
230+
231+ cat <<'EOF' > "$TEMP_CHANGELOG"
232+ ${{ needs.version.outputs.changelog }}
233+ EOF
234+
235+ if [ -f "$CHANGELOG_FILE" ]; then
236+ printf "\n" >> "$TEMP_CHANGELOG"
237+ cat "$CHANGELOG_FILE" >> "$TEMP_CHANGELOG"
238+ fi
239+
240+ mv "$TEMP_CHANGELOG" "$CHANGELOG_FILE"
241+
242+ - name : Commit and Push Changelog
243+ env :
244+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
245+ run : |
246+ set -euo pipefail
247+
248+ # Pull latest changes (version job pushed new commits)
249+ git pull origin ${{ github.ref_name }} --rebase
250+
251+ if git diff --quiet -- CHANGELOG.md; then
252+ echo "No changelog updates to commit."
253+ exit 0
254+ fi
255+
256+ git add CHANGELOG.md
257+ git commit -m "chore: update changelog for ${{ needs.version.outputs.new_version }}"
258+ git push origin HEAD:${{ github.ref_name }}
259+
260+ - name : Download all build artifacts
261+ uses : actions/download-artifact@v4
262+ with :
263+ path : artifacts
264+
265+ - name : Prepare Release Assets
266+ run : |
267+ mkdir -p release-assets
268+ find artifacts -type f \( -name "*.deb" -o -name "*.AppImage" -o -name "*.msi" -o -name "*.dmg" \) -exec cp {} release-assets/ \; || true
269+
270+ if [ -d "artifacts/Tauri Build Artifacts (macos-latest)/src-tauri/target/release/bundle/macos" ]; then
271+ MACOS_BUNDLE_DIR="artifacts/Tauri Build Artifacts (macos-latest)/src-tauri/target/release/bundle/macos"
272+ cd "$MACOS_BUNDLE_DIR"
273+ shopt -s nullglob
274+ apps=( *.app )
275+ if [ ${#apps[@]} -gt 0 ]; then
276+ for app in "${apps[@]}"; do
277+ zip -r "$GITHUB_WORKSPACE/release-assets/${app%.app}.zip" "$app"
278+ done
279+ fi
280+ cd -
281+ fi
282+
283+ echo "Prepared release assets:"
284+ ls -l release-assets/
285+
286+ - name : Install GitHub CLI
287+ run : |
288+ type -p curl >/dev/null || (sudo apt update && sudo apt install curl -y)
289+ curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
290+ && sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
291+ && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
292+ && sudo apt update \
293+ && sudo apt install gh -y
294+
295+ - name : Create GitHub Release
296+ env :
297+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
298+ run : |
299+ set -euo pipefail
300+
301+ NEW_VERSION="${{ needs.version.outputs.new_version }}"
302+ echo "Creating release: $NEW_VERSION"
303+
304+ CHANGELOG_NOTES_FILE="RELEASE_NOTES.md"
305+ cat <<'EOF' > "$CHANGELOG_NOTES_FILE"
306+ ${{ needs.version.outputs.changelog }}
307+ EOF
308+
309+ gh release create "$NEW_VERSION" \
310+ --title "CircuitVerse Desktop $NEW_VERSION" \
311+ --notes-file "$CHANGELOG_NOTES_FILE" \
312+ release-assets/*
0 commit comments