Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
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
102 changes: 77 additions & 25 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ on:
type: boolean

env:
CN_APPLICATION: cap/cap
APP_CARGO_TOML: apps/desktop/src-tauri/Cargo.toml
SENTRY_ORG: cap-s2
SENTRY_PROJECT: cap-desktop
Expand All @@ -35,7 +34,6 @@ jobs:
outputs:
version: ${{ steps.read_version.outputs.value }}
needs_release: ${{ steps.create_tag.outputs.tag_existed != 'true' }}
cn_release_stdout: ${{ steps.create_cn_release.outputs.stdout }}
gh_release_url: ${{ steps.create_gh_release.outputs.url }}
permissions:
contents: write
Expand Down Expand Up @@ -100,13 +98,6 @@ jobs:

await main();

- name: Create draft CN release
id: create_cn_release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} ${{ steps.read_version.outputs.value }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}

- name: Create draft GH release
id: create_gh_release
# TODO: Change to stable version when available
Expand All @@ -124,7 +115,6 @@ jobs:
script: |
async function main() {
const token = await core.getIDToken("cap-discord-bot");
const cnReleaseId = JSON.parse(`${{ steps.create_cn_release.outputs.stdout }}`).id;

const resp = await fetch(
"https://cap-discord-bot.brendonovich.workers.dev/github-workflow",
Expand All @@ -136,7 +126,6 @@ jobs:
version: "${{ steps.read_version.outputs.value }}",
releaseUrl: "${{ steps.create_gh_release.outputs.url }}",
interactionId: "${{ inputs.interactionId }}",
cnReleaseId,
}),
headers: {
"Content-Type": "application/json",
Expand Down Expand Up @@ -171,11 +160,11 @@ jobs:
platform: macos
arch: arm64
- target: x86_64-pc-windows-msvc
runner: windows-latest-l
runner: windows-latest
platform: windows
arch: x64
- target: aarch64-pc-windows-msvc
runner: windows-latest-l
runner: windows-latest
platform: windows
arch: arm64
env:
Expand All @@ -188,6 +177,25 @@ jobs:
if: ${{ env.RUN_BUILD == 'true' }}
uses: actions/checkout@v4

- name: Normalize Cargo version
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor workflow gotcha: the draft job reads apps/desktop/src-tauri/Cargo.toml and creates the tag before this runs. So if the version ever accidentally becomes cap-vX, this step would normalize only for the build while the tag would still become cap-vcap-vX.

I’d either move this normalization into draft (before Read version number) or make this step fail fast instead of mutating the file.

if: ${{ env.RUN_BUILD == 'true' }}
Comment on lines 169 to +181
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 All non-ARM artifact uploads have been removed

The original crabnebula-dev/cloud-release upload step ran for every build matrix entry (macOS arm64, macOS x64, Windows x64, Windows arm64). The replacement actions/upload-artifact@v4 step is conditioned on platform == 'windows' && arch == 'arm64' only. This means macOS and Windows x64 builds now produce no uploaded artifacts at all, which will break those release pipelines entirely.

Either restore the upload step for other platforms or add an else branch that handles the non-ARM case.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/publish.yml
Line: 169-181

Comment:
**All non-ARM artifact uploads have been removed**

The original `crabnebula-dev/cloud-release` upload step ran for every build matrix entry (macOS arm64, macOS x64, Windows x64, Windows arm64). The replacement `actions/upload-artifact@v4` step is conditioned on `platform == 'windows' && arch == 'arm64'` only. This means macOS and Windows x64 builds now produce no uploaded artifacts at all, which will break those release pipelines entirely.

Either restore the upload step for other platforms or add an `else` branch that handles the non-ARM case.

How can I resolve this? If you propose a fix, please make it concise.

shell: bash
run: |
node <<'NODE'
const fs = require('node:fs');
const cargoTomlPath = 'apps/desktop/src-tauri/Cargo.toml';
const contents = fs.readFileSync(cargoTomlPath, 'utf8');
const normalized = contents.replace(
/^version\s*=\s*"cap-v([^"]+)"$/m,
'version = "$1"',
);

if (normalized !== contents) {
fs.writeFileSync(cargoTomlPath, normalized);
console.log(`Normalized ${cargoTomlPath} to semver`);
}
NODE

- name: Create API Key File
if: ${{ env.RUN_BUILD == 'true' }}
run: echo "${{ secrets.APPLE_API_KEY_FILE }}" > api.p8
Expand Down Expand Up @@ -229,12 +237,61 @@ jobs:
echo 'VITE_SERVER_URL=${{ secrets.NEXT_PUBLIC_WEB_URL }}' >> .env
echo 'RUST_TARGET_TRIPLE=${{ matrix.settings.target }}' >> .env

- name: Prepare Tauri build config
if: ${{ env.RUN_BUILD == 'true' }}
shell: node {0}
env:
RAW_TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
run: |
const fs = require("node:fs");
const path = require("node:path");

const workspace = process.env.GITHUB_WORKSPACE;
const sourceConfigPath = path.join(workspace, "apps/desktop/src-tauri/tauri.prod.conf.json");
const buildConfigPath = path.join(workspace, "apps/desktop/src-tauri/tauri.build.conf.json");
const config = JSON.parse(fs.readFileSync(sourceConfigPath, "utf8"));

const raw = (process.env.RAW_TAURI_SIGNING_PRIVATE_KEY || "").trim();
const candidates = raw
? new Set([raw, raw.replace(/\\n/g, "\n")])
: new Set();

if (raw && /^[A-Za-z0-9+/=\r\n]+$/.test(raw) && !raw.includes("untrusted comment:")) {
try {
const decoded = Buffer.from(raw.replace(/\s+/g, ""), "base64").toString("utf8");
candidates.add(decoded);
candidates.add(decoded.replace(/\\n/g, "\n"));
} catch {}
}

const key = [...candidates].find(
(value) =>
value.includes("untrusted comment:") &&
value.toLowerCase().includes("minisign secret key"),
);
Comment on lines +267 to +271
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor robustness: this untrusted comment: check is case-sensitive, while the next check lowercases. Making both case-insensitive avoids unexpectedly disabling updater artifacts if the secret formatting changes slightly.

Suggested change
const key = [...candidates].find(
(value) =>
value.includes("untrusted comment:") &&
value.toLowerCase().includes("minisign secret key"),
);
const key = [...candidates].find((value) => {
const lower = value.toLowerCase();
return lower.includes("untrusted comment:") && lower.includes("minisign secret key");
});


if (key) {
fs.appendFileSync(
process.env.GITHUB_ENV,
`TAURI_SIGNING_PRIVATE_KEY<<__TAURI_KEY__\n${key}\n__TAURI_KEY__\n`,
);
} else {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the signing key is missing/invalid this silently disables updater + artifacts, which can be pretty confusing to debug from logs. Consider emitting a warning here.

Suggested change
} else {
} else {
console.warn("TAURI_SIGNING_PRIVATE_KEY missing/invalid; disabling updater and updater artifacts");

config.plugins ??= {};
config.plugins.updater ??= {};
config.plugins.updater.active = false;

config.bundle ??= {};
config.bundle.createUpdaterArtifacts = false;
}

fs.writeFileSync(buildConfigPath, `${JSON.stringify(config, null, 2)}\n`);

- name: Build app
if: ${{ env.RUN_BUILD == 'true' }}
working-directory: apps/desktop
run: |
pnpm -w cap-setup
pnpm build:tauri --target ${{ matrix.settings.target }} --config src-tauri/tauri.prod.conf.json
pnpm build:tauri --target ${{ matrix.settings.target }} --config src-tauri/tauri.build.conf.json
env:
# https://github.com/tauri-apps/tauri-action/issues/740
CI: false
Expand All @@ -248,7 +305,6 @@ jobs:
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
APPLE_API_KEY_PATH: ${{ github.workspace }}/api.p8
APPLE_KEYCHAIN: ${{ runner.temp }}/build.keychain
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}

# - name: Upload unsigned Windows installer
Expand Down Expand Up @@ -297,15 +353,13 @@ jobs:
# Write-Host "Files in bundle directory after signing:"
# Get-ChildItem -Path $bundleDir -Filter *.exe | ForEach-Object { Write-Host " - $($_.Name)" }

- name: Upload assets
if: ${{ env.RUN_BUILD == 'true' }}
uses: crabnebula-dev/cloud-release@v0
- name: Upload Windows ARM installer artifact
if: ${{ env.RUN_BUILD == 'true' && matrix.settings.platform == 'windows' && matrix.settings.arch == 'arm64' }}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This upload step is gated to Windows ARM only, so Windows x64 (and macOS) builds won't upload any artifacts anymore. If the goal is just to add ARM support, consider uploading for all Windows matrix entries (and adding similar uploads for macOS), or restoring the previous release upload.

Suggested change
if: ${{ env.RUN_BUILD == 'true' && matrix.settings.platform == 'windows' && matrix.settings.arch == 'arm64' }}
- name: Upload Windows installer artifact
if: ${{ env.RUN_BUILD == 'true' && matrix.settings.platform == 'windows' }}
uses: actions/upload-artifact@v4
with:
name: windows-${{ matrix.settings.arch }}-installer
path: target/${{ matrix.settings.target }}/release/bundle/nsis/*.exe
if-no-files-found: error

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This upload step only runs for Windows ARM64, so the other matrix entries won’t publish any artifacts. If the intent is to keep artifacts for every build, consider uploading per target/arch with a dynamic name.

Suggested change
if: ${{ env.RUN_BUILD == 'true' && matrix.settings.platform == 'windows' && matrix.settings.arch == 'arm64' }}
- name: Upload build artifacts
if: ${{ env.RUN_BUILD == 'true' }}
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.settings.platform }}-${{ matrix.settings.arch }}-bundle
path: target/${{ matrix.settings.target }}/release/bundle/**
if-no-files-found: error

uses: actions/upload-artifact@v4
with:
working-directory: apps/desktop
command: release upload ${{ env.CN_APPLICATION }} "${{ needs.draft.outputs.version }}" --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
env:
TAURI_BUNDLE_PATH: ../..
name: windows-arm-installer
path: target/${{ matrix.settings.target }}/release/bundle/nsis/*.exe
if-no-files-found: error
Comment on lines +356 to +362
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now this only uploads an artifact for Windows ARM, so the other matrix builds (macOS, Windows x64) end up with no uploaded bundle at all. If the goal is just to add ARM support, it’d be nice to keep artifacts for the other targets too.

Suggested change
- name: Upload Windows ARM installer artifact
if: ${{ env.RUN_BUILD == 'true' && matrix.settings.platform == 'windows' && matrix.settings.arch == 'arm64' }}
uses: actions/upload-artifact@v4
with:
working-directory: apps/desktop
command: release upload ${{ env.CN_APPLICATION }} "${{ needs.draft.outputs.version }}" --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
env:
TAURI_BUNDLE_PATH: ../..
name: windows-arm-installer
path: target/${{ matrix.settings.target }}/release/bundle/nsis/*.exe
if-no-files-found: error
- name: Upload Tauri bundle artifacts
if: ${{ env.RUN_BUILD == 'true' }}
uses: actions/upload-artifact@v4
with:
name: tauri-${{ matrix.settings.platform }}-${{ matrix.settings.arch }}
path: |
target/${{ matrix.settings.target }}/release/bundle/nsis/*.exe
target/${{ matrix.settings.target }}/release/bundle/dmg/*.dmg
if-no-files-found: error


- uses: matbour/setup-sentry-cli@8ef22a4ff03bcd1ebbcaa3a36a81482ca8e3872e
if: ${{ env.RUN_BUILD == 'true' }}
Expand Down Expand Up @@ -340,7 +394,6 @@ jobs:
script: |
async function main() {
const token = await core.getIDToken("cap-discord-bot");
const cnReleaseId = JSON.parse(`${{ needs.draft.outputs.cn_release_stdout }}`).id;

const resp = await fetch(
"https://cap-discord-bot.brendonovich.workers.dev/github-workflow",
Expand All @@ -351,7 +404,6 @@ jobs:
interactionId: "${{ inputs.interactionId }}",
version: "${{ needs.draft.outputs.version }}",
releaseUrl: "${{ needs.draft.outputs.gh_release_url }}",
cnReleaseId,
}),
headers: {
"Content-Type": "application/json",
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/desktop/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cap-desktop"
version = "0.3.83"
version = "0.4.87"
description = "Beautiful screen recordings, owned by you."
authors = ["you"]
edition = "2024"
Expand Down
6 changes: 4 additions & 2 deletions apps/desktop/src-tauri/src/recording.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use crate::{
auth::AuthStore,
create_screenshot,
general_settings::{
self, GeneralSettingsStore, PostDeletionBehaviour, PostStudioRecordingBehaviour,
GeneralSettingsStore, PostDeletionBehaviour, PostStudioRecordingBehaviour,
},
open_external_link,
presets::PresetsStore,
Expand Down Expand Up @@ -502,7 +502,9 @@ pub async fn start_recording(
general_settings
.map(|s| s.custom_cursor_capture)
.unwrap_or_default(),
);
)
.with_fragmented(false)
.with_max_fps(60);

#[cfg(target_os = "macos")]
{
Expand Down
File renamed without changes.
3 changes: 3 additions & 0 deletions crates/project/src/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ impl Default for Platform {

#[cfg(target_os = "macos")]
return Self::MacOS;

#[cfg(not(any(windows, target_os = "macos")))]
return Self::Windows;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes non-Windows/non-macOS builds report Platform::Windows, which seems like it could silently mis-label recordings (or enable Windows-only behavior) if someone builds tooling on Linux.

Suggested change
return Self::Windows;
#[cfg(not(any(windows, target_os = "macos")))]
compile_error!("Unsupported platform");

Comment on lines +60 to +62
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For non-Windows and non-macOS targets, Platform::default() now returns Platform::Windows. That will misreport the platform on Linux/other builds and may leak into persisted metadata. If other platforms are supported, consider adding an explicit Linux/Unknown variant (or returning None at call sites) rather than defaulting to Windows.

Copilot uses AI. Check for mistakes.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defaulting to Windows on non-Windows/non-macOS targets will silently mislabel metadata. If Linux/other targets aren’t supported, I’d rather make this loud than lie.

Suggested change
return Self::Windows;
return unreachable!("unsupported platform");

}
Comment on lines +61 to 63
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Incorrect fallback platform for Linux/other OSes

The #[cfg(not(any(windows, target_os = "macos")))] branch returns Self::Windows for any non-Windows, non-macOS platform (e.g., Linux). This means Linux builds would silently report their platform as Windows, which is semantically wrong and could cause incorrect behaviour in any code that branches on the Platform value.

A Platform::Linux variant (or at minimum Platform::Unknown) should be used here. If Linux is not a supported target for the desktop app, this case should panic or return an error rather than silently lying.

Suggested change
#[cfg(not(any(windows, target_os = "macos")))]
return Self::Windows;
}
#[cfg(not(any(windows, target_os = "macos")))]
return Self::Linux;
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/project/src/meta.rs
Line: 61-63

Comment:
**Incorrect fallback platform for Linux/other OSes**

The `#[cfg(not(any(windows, target_os = "macos")))]` branch returns `Self::Windows` for any non-Windows, non-macOS platform (e.g., Linux). This means Linux builds would silently report their platform as `Windows`, which is semantically wrong and could cause incorrect behaviour in any code that branches on the `Platform` value.

A `Platform::Linux` variant (or at minimum `Platform::Unknown`) should be used here. If Linux is not a supported target for the desktop app, this case should panic or return an error rather than silently lying.

```suggestion
        #[cfg(not(any(windows, target_os = "macos")))]
        return Self::Linux;
```

How can I resolve this? If you propose a fix, please make it concise.

}

Expand Down
Loading