@@ -46,16 +46,20 @@ jobs:
4646 bun-version : latest
4747
4848 - name : Install Rust toolchain
49- uses : dtolnay/rust-toolchain@stable
49+ shell : bash
50+ run : |
51+ rustup toolchain install stable --profile minimal
52+ rustup component add --toolchain stable rustfmt clippy
53+ rustup default stable
5054
5155 - name : Cache Rust
5256 uses : actions/cache@v4
5357 with :
5458 path : |
5559 ~/.cargo/registry
5660 ~/.cargo/git
57- target
58- key : ${{ runner.os }}-cargo-${{ hashFiles('** /Cargo.lock') }}
61+ apps/desktop/src-tauri/ target
62+ key : ${{ runner.os }}-cargo-${{ hashFiles('apps/desktop/src-tauri /Cargo.lock') }}
5963 restore-keys : ${{ runner.os }}-cargo-
6064
6165 - name : Install Linux system deps (Tauri)
@@ -143,14 +147,127 @@ jobs:
143147 with :
144148 path : dist-artifacts
145149
146- - name : Release
147- uses : softprops/action-gh-release@v2
150+ - name : Set release metadata
151+ id : release_meta
152+ env :
153+ VERSION : ${{ steps.ver.outputs.version }}
154+ PRERELEASE_INPUT : ${{ inputs.prerelease || 'false' }}
155+ run : |
156+ version="$VERSION"
157+ prerelease_input="$PRERELEASE_INPUT"
158+ is_prerelease=false
159+ if [ "$prerelease_input" = "true" ]; then
160+ is_prerelease=true
161+ elif [[ "$version" == *"-rc"* ]]; then
162+ is_prerelease=true
163+ fi
164+ echo "prerelease=$is_prerelease" >> "$GITHUB_OUTPUT"
165+
166+ - name : Publish release
167+ id : publish_release
168+ uses : actions/github-script@v7
148169 with :
149- tag_name : ${{ steps.ver.outputs.version }}
150- name : Open With Browser ${{ steps.ver.outputs.version }}
151- prerelease : ${{ github.event.inputs.prerelease == 'true' || contains(steps.ver.outputs.version, '-rc') }}
152- draft : false
153- generate_release_notes : true
154- files : |
155- dist-artifacts/**
170+ github-token : ${{ secrets.GITHUB_TOKEN }}
171+ script : |
172+ const fs = require('fs');
173+ const path = require('path');
174+
175+ const version = process.env.RELEASE_VERSION;
176+ if (!version) {
177+ core.setFailed('RELEASE_VERSION not provided');
178+ return;
179+ }
180+
181+ const artifactsDir = process.env.ARTIFACTS_DIR;
182+ if (!artifactsDir || !fs.existsSync(artifactsDir)) {
183+ core.warning(`Artifacts directory "${artifactsDir}" not found, skipping asset upload.`);
184+ return;
185+ }
186+
187+ const walk = (dir) => {
188+ const entries = fs.readdirSync(dir, { withFileTypes: true });
189+ return entries.flatMap((entry) => {
190+ const fullPath = path.join(dir, entry.name);
191+ if (entry.isDirectory()) {
192+ return walk(fullPath);
193+ }
194+ if (entry.isFile()) {
195+ return [fullPath];
196+ }
197+ return [];
198+ });
199+ };
200+
201+ const files = walk(artifactsDir);
202+ if (files.length === 0) {
203+ core.warning(`No files found under "${artifactsDir}" to upload.`);
204+ return;
205+ }
206+
207+ const owner = context.repo.owner;
208+ const repo = context.repo.repo;
209+ const tagName = version;
210+ const releaseName = `Open With Browser ${version}`;
211+ const prerelease = process.env.PRERELEASE_FLAG === 'true';
212+
213+ let release;
214+ try {
215+ const existing = await github.rest.repos.getReleaseByTag({ owner, repo, tag: tagName });
216+ release = existing.data;
217+ core.info(`Found existing release for ${tagName}, reusing it.`);
218+ } catch (error) {
219+ if (error.status === 404) {
220+ core.info(`Creating new release for ${tagName}.`);
221+ const created = await github.rest.repos.createRelease({
222+ owner,
223+ repo,
224+ tag_name: tagName,
225+ name: releaseName,
226+ draft: false,
227+ prerelease,
228+ generate_release_notes: true,
229+ });
230+ release = created.data;
231+ } else {
232+ throw error;
233+ }
234+ }
235+
236+ if (release.assets && release.assets.length > 0) {
237+ core.info(`Removing ${release.assets.length} existing asset(s).`);
238+ for (const asset of release.assets) {
239+ await github.rest.repos.deleteReleaseAsset({
240+ owner,
241+ repo,
242+ asset_id: asset.id,
243+ });
244+ }
245+ }
246+
247+ for (const file of files) {
248+ const stats = fs.statSync(file);
249+ if (!stats.isFile()) {
250+ continue;
251+ }
252+ const relativePath = path.relative(artifactsDir, file).replace(/\\/g, '/');
253+ const assetName = relativePath.replace(/\//g, '-');
254+ core.info(`Uploading ${assetName}`);
255+ await github.rest.repos.uploadReleaseAsset({
256+ owner,
257+ repo,
258+ release_id: release.id,
259+ name: assetName,
260+ headers: {
261+ 'content-type': 'application/octet-stream',
262+ 'content-length': stats.size,
263+ },
264+ data: fs.readFileSync(file),
265+ });
266+ }
267+
268+ core.setOutput('release_url', release.html_url);
269+ env :
270+ RELEASE_VERSION : ${{ steps.ver.outputs.version }}
271+ PRERELEASE_FLAG : ${{ steps.release_meta.outputs.prerelease }}
272+ ARTIFACTS_DIR : dist-artifacts
156273 if : startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
0 commit comments