Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 207 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
# https://github.com/tauri-apps/tauri-action
name: Release

on:
push:
branches:
- main

jobs:
preflight:
name: Preflight — check if release already exists
permissions:
contents: read
runs-on: ubuntu-latest
outputs:
skip: ${{ steps.check.outputs.skip }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Check for existing tag/release v__VERSION__
id: check
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const path = require('path');
const cfgPath = path.join(process.cwd(), 'src-tauri', 'tauri.conf.json');
let version = '';
try {
const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
version = cfg.version || '';
} catch (e) {
core.info(`Failed reading ${cfgPath}: ${e.message}`);
}
if (!version) {
try {
const pkg = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8'));
version = pkg.version || '';
} catch (e) {
core.info(`Failed reading package.json: ${e.message}`);
}
}
if (!version) {
core.setFailed('Unable to determine version from src-tauri/tauri.conf.json or package.json');
return;
}
const tagName = `v${version}`;
core.info(`Checking if tag or release exists for ${tagName} ...`);

try {
await github.rest.git.getRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `tags/${tagName}`,
});
core.info(`Tag ${tagName} already exists. Skipping release.`);
core.setOutput('skip', 'true');
return;
} catch (e) {
if (e.status !== 404) throw e;
}
const releases = await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100,
});
const found = releases.data.find(r => r.tag_name === tagName);
if (found) {
core.info(`Release with tag ${tagName} already exists. Skipping release.`);
core.setOutput('skip', 'true');
return;
}
core.info(`OK: ${tagName} does not exist. Proceeding with release.`);
core.setOutput('skip', 'false');

publish-tauri:
needs: preflight
if: needs.preflight.outputs.skip != 'true'
permissions:
contents: write
strategy:
fail-fast: false
matrix:
include:
- platform: 'macos-latest'
args: '--target aarch64-apple-darwin'
- platform: 'macos-latest'
args: '--target x86_64-apple-darwin'
- platform: 'windows-latest'
args: '--bundles nsis'

runs-on: ${{ matrix.platform }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Install Rust (stable)
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}

- name: Cache Rust
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
src-tauri/target
key: ${{ runner.os }}-cargo-${{ hashFiles('src-tauri/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-

- name: Install frontend dependencies
run: npm ci

- name: Build and publish with Tauri
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
with:
tagName: v__VERSION__
releaseName: 'v__VERSION__'
releaseBody: 'See the assets to download this version and install.'
releaseDraft: false
prerelease: false
generateReleaseNotes: true
includeUpdaterJson: true
updaterJsonPreferNsis: true
args: ${{ matrix.args }}

upload-stable-assets:
name: Upload fixed-name assets for README links
needs: publish-tauri
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Upload fixed-name copies
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const cfg = JSON.parse(fs.readFileSync('src-tauri/tauri.conf.json', 'utf8'));
const version = cfg.version;
const tag = `v${version}`;

const { data: release } = await github.rest.repos.getReleaseByTag({
owner: context.repo.owner,
repo: context.repo.repo,
tag,
});

// Mapping: versioned asset name pattern → fixed name
const renames = [
{ match: `_${version}_aarch64.dmg`, fixedName: 'Scripta_macOS_arm64.dmg' },
{ match: `_${version}_x64.dmg`, fixedName: 'Scripta_macOS_x64.dmg' },
{ match: `_${version}_x64-setup.exe`, fixedName: 'Scripta_Windows_x64-setup.exe' },
];

// Remove old fixed-name assets if they exist from a previous run
for (const { fixedName } of renames) {
const existing = release.assets.find(a => a.name === fixedName);
if (existing) {
await github.rest.repos.deleteReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
asset_id: existing.id,
});
core.info(`Deleted old asset: ${fixedName}`);
}
}

for (const { match, fixedName } of renames) {
const asset = release.assets.find(a => a.name.endsWith(match));
if (!asset) {
core.warning(`Asset matching *${match} not found, skipping ${fixedName}`);
continue;
}
// Download the versioned asset
const download = await github.rest.repos.getReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
asset_id: asset.id,
headers: { accept: 'application/octet-stream' },
});
// Upload with fixed name
const uploadUrl = release.upload_url;
await github.rest.repos.uploadReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: release.id,
name: fixedName,
data: Buffer.from(download.data),
});
core.info(`Uploaded ${fixedName} (from ${asset.name})`);
}
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,11 @@ Scripta remembers which note you had open, where you were scrolled to, and where

Download the latest version from the [Releases](https://github.com/j4rviscmd/Scripta/releases/latest) page.

- **macOS**: Download the `.dmg` file
- **Windows**: Download the `.msi` installer
| Platform | Download |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **macOS (Apple Silicon)** | [Scripta_macOS_arm64.dmg](https://github.com/j4rviscmd/Scripta/releases/latest/download/Scripta_macOS_arm64.dmg) |
| **macOS (Intel)** | [Scripta_macOS_x64.dmg](https://github.com/j4rviscmd/Scripta/releases/latest/download/Scripta_macOS_x64.dmg) |
| **Windows** | [Scripta_Windows_x64-setup.exe](https://github.com/j4rviscmd/Scripta/releases/latest/download/Scripta_Windows_x64-setup.exe) |

> [!NOTE]
> macOS builds are not signed. On first launch, run:
Expand Down
Loading
Loading