Commit Graph

275 Commits

Author SHA1 Message Date
Matt Fiddaman
88e1e5fc17 prevent duplicate draft releases (#8381)
* prevent duplicate draft releases

* note
2026-07-04 12:22:39 +00:00
Matt Fiddaman
d56cb52161 speed up electron builds (#8337)
* size up runners, skip translations where possible

* note
2026-06-26 13:14:54 +00:00
Matiss Janis Aboltins
c4acaa2951 [AI] Add knip to detect unused files, dependencies and exports (#8309)
Adds the knip tool with a monorepo-tuned config (knip.json) and a CI gate
in check.yml, plus the dead-code and dependency cleanup it surfaced. The
unused-export/type/duplicate rules are disabled so exporting an unused
symbol is allowed.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 22:11:48 +00:00
Matt Fiddaman
c4775bf288 wire tests up to depot test results analysis (#8262)
* emit junit files

* wire up the actions

* note

* [autofix.ci] apply automated fixes

* fix overly broad error

* scope to master runs

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-06-21 07:50:55 +00:00
Matiss Janis Aboltins
8f27e177dc [AI] api: add browser build (#8166)
* [AI] api: add browser build

Continuation of #7545 (and #8143, which moved the browser Web Worker
bootstrap into loot-core). This adds the browser-compatible build of
@actual-app/api: the full loot-core stack runs inside a Web Worker and a
thin main-thread facade exposes the same public surface as the Node entry.

loot-core:
- Add platform/client/backend-worker.ts: createBackendWorker(worker)
  centralizes absurd-sql's main-thread initBackend + __absurd:* message
  filtering, and is exported for the api to reuse.
- Refactor browser-preload's start.ts and worker-bridge.ts to route through
  it (drops the duplicated __absurd:* filtering; terminate() now also clears
  listeners). Behavior is preserved.

api:
- browser-worker.ts: Web Worker entry owning real loot-core, speaking
  loot-core's {id,name,args} backend protocol; wraps fetch to map the
  .js -> .js.data migration names.
- index.browser.ts: main-thread facade that spawns the worker.
- browser/rpc.ts: main-thread <-> worker RPC bridge (uses createBackendWorker).
- browser/lib-stub.ts: stubs lib.send so methods.ts routes over postMessage.
- vite.browser.config.mts / vite.browser-worker.config.mts and asset bundling
  in vite.config.mts (sql-wasm.wasm + data/ + data-file-index.txt); package.json
  build chain, browser export, and absurd-sql/npm-run-all/vite-plugin-node-polyfills deps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] Rename release note to match PR number 8166

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] api: move browser worker plumbing into loot-core

Address review feedback: the browser worker logic shouldn't live in the api
package since it's generic "loot-core as a browser npm package" plumbing, not
api-specific. Resolve it via loot-core's existing conditional-export system
instead of a vite alias.

- loot-core: add server/main.api-browser.ts (worker-routing `lib` that
  delegates to the existing platform/client/connection), selected via a new
  `api-browser` export condition on "./server/main". Move the worker entry to
  server/api-browser-worker.ts.
- api: the facade (index.browser.ts) now reuses loot-core's client connection
  via a minimal global.Actual.getServerSocket shim and spawns the worker built
  from loot-core's entry. Deletes browser-worker.ts, browser/rpc.ts and
  browser/lib-stub.ts (~270 lines) in favor of the shared loot-core code.
- The facade build selects the impl with resolve.conditions: ['api-browser']
  instead of resolve.alias, removing the enforce-boundaries lint exception.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] api: simplify browser build cleanups

Post-review cleanups (no behavior change):
- backend-worker.ts: fix stale doc comment referencing the removed
  packages/api/browser/rpc.ts (the consumer is now index.browser.ts).
- api-browser-worker.ts: drop the redundant `endsWith('/data-file-index.txt')`
  disjunct (subsumed by `endsWith('data-file-index.txt')`) and the no-op
  `input as RequestInfo | URL` re-casts on the fetch pass-throughs.
- index.browser.ts: replace the single-field `state` holder with a plain
  module-level `let backend`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] api: drop the createBackendWorker wrapper, revert browser-preload churn

Now that the facade rides on loot-core's platform/client/connection (which
already ignores absurd-sql's `__`-prefixed internal messages), the only thing
the main thread still needs is absurd's one-line initBackend. So:

- Replace the 60-line createBackendWorker wrapper (onMessage/postMessage/
  terminate/listener filtering) with a tiny initBrowserBackend(worker) helper.
- Revert browser-preload/start.ts and worker-bridge.ts to their merged state —
  they keep importing absurd's initBackend directly, so this PR no longer
  refactors just-merged files and the loot-core change is purely additive.
- Facade holds a plain Worker handle and calls worker.terminate() on shutdown.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] api: trim verbose comments in the browser build

Keep only the load-bearing "why" notes (the absurd-sql init, the fetch/.js.data
workaround, the global.Actual shim, the api-browser condition); drop protocol
diagrams, usage examples, and restated context. No code/behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] api: drop redundant absurd-sql dependency

No api source imports absurd-sql; it's reached only through @actual-app/core
(the facade's initBrowserBackend and the bundled worker), which declares it.
It's bundled into the build output, so it isn't a runtime dependency of the
published package either. Bundles are byte-for-byte unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] api: drop the api-browser condition, inject the worker into the connection

Review feedback: the api-browser export condition fought loot-core's idiom
(browser IS the default platform; node/"api" is the override) and hid a bug —
the condition-swapped lib only had `send`, so api.utils.amountToInteger was
silently undefined in the browser build.

Replace the condition with a plain transport seam:
- methods.ts no longer imports server/main; it sends through api/send.ts,
  which the Node entry wires to in-process lib.send and the browser entry
  wires to loot-core's client connection. utils.ts re-exports
  amountToInteger/integerToAmount from shared/util directly (fixes the bug).
- loot-core's client connection init() now accepts an optional injected
  socket; connectBackendWorker(worker) installs absurd-sql's bridge and
  connects in one call. This removes the forged global.Actual shim and the
  facade's `define: { global: 'globalThis' }` workaround. Desktop's argless
  init() path is unchanged.
- Delete main.api-browser.ts, the "./server/main" conditional export, and
  the facade's resolve.conditions.

The 4 loot-core snapshot failures (main.test.ts / transfer.test.ts) are
pre-existing on the branch without these changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] api: route methods through the client connection, slim the facade

Review feedback: get rid of the _setSend seam and move the worker init logic
into loot-core.

- methods.ts now imports `send` from loot-core's client connection. The node
  build resolves it via the existing `api` condition to a new in-process
  implementation (platform/client/connection/index.api.ts — previously a dead
  re-export of the electron client), matching the platform idiom: browser is
  the default, node/"api" overrides. api/send.ts is deleted and the node
  entry (index.ts) reverts to master byte-for-byte.
- loot-core's startBackendWorker(worker, config, assetsBaseUrl) now owns the
  whole worker boot (absurd-sql bridge + connection.init + server init RPC),
  so the browser entry just spawns the worker and calls it.
- Trims: single chained build script (drops the npm-run-all dep), copyFileSync
  instead of the linkOrCopy helper, drop the worker entry's error listeners
  (browsers already log worker uncaughts to DevTools).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] api: trim prose comments to the essential ones

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] fix client connection stalling when no sends are queued at connect

Found while smoke-testing the browser api build in a real consumer app: the
client connection only nulled messageQueue (switching from queueing to direct
postMessage) when the queue was non-empty at 'connect'. The desktop app always
has queued sends by then, so it never hits this; the api facade connects
before sending anything, so every later send queued forever and init() hung.
Drop the queue on connect unconditionally.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] fix client connection dropping api/* error replies

Found via the browser smoke test: opening an e2e-encrypted budget without the
key surfaced as "undefined is not an object" instead of an error. The server
connection forwards api/* handler failures as {type:'reply', id, error}, but
the web client connection only read `result`, silently resolving undefined for
every failed api/* call. Reject when the reply carries an error, matching the
server's envelope (and the old api rpc behavior). The electron client has the
same latent gap; left untouched here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] api: move the worker entry back into the api package

Review feedback: browser-worker.ts is the api package's build entry, not
generic loot-core code — move it back (it now imports loot-core through the
public @actual-app/core exports instead of #-subpaths).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] api: drop the manifest rewrite, align shutdown, trim comments

The data-file-index.txt manifest now lists migrations under their real .js
names (the worker's fetch shim already redirects those to the .js.data files
on disk), so the manifest-rewriting half of the shim is gone. The worker init
payload carries config and assetsBaseUrl as separate fields instead of
smuggling a private key into the config object, browser shutdown() mirrors
the node facade, and the client connection's queue flush drops a redundant
branch.

* [AI] fix rejected handler promises poisoning close-budget

runHandler only removed a method's promise from runningMethods when it
fulfilled, so any handler rejection left a stale promise in the set. The next
close-budget then failed: flushRunningMethods' Promise.all rejected with that
old, unrelated error before closeBudget even ran. Remove settled promises on
rejection too, and flush with Promise.allSettled since rejected methods
already reported their error to their caller.

* [AI] api: add a browser e2e test

A Playwright test loads the built browser bundle in chromium from a static
COOP/COEP server and exercises the full stack: worker boot, the rejected-error
contract, budget import, transaction read-back, and IndexedDB persistence
across a page reload. A dedicated workflow runs it in CI on api/loot-core
changes.

* [AI] api: drop the worker fetch shim; strip .data names in loot-core fs

The .js.data scheme was spread across three coordinated pieces: the build
renamed migrations on disk, the manifest listed names that didn't exist, and
a global fetch monkey-patch in the worker un-lied at runtime. Now the
manifest lists the true on-disk names and populateDefaultFilesystem (the only
fetcher of these files) strips the .data suffix when naming the virtual file
— the fetch patch is gone and the suffix becomes a small documented fs
convention. Also: e2e static server uses a single stat and drops a dead MIME
entry.

* [AI] fix electron client connection dropping api/* error replies

Both server connection variants post api/* handler failures as
{type: 'reply', id, error}, but only the web client rejected on it
(778ed25cf); the electron renderer client still resolved undefined. Mirror
the check so the wire contract is implemented uniformly.

* [AI] api: exclude the playwright e2e from vitest; review polish

vitest's default include matched e2e/browser.test.ts and failed CI - a
playwright test file defines no vitest tests. Exclude e2e/ from the unit-test
run (it has its own yarn e2e script). Also from review: the browser exports
condition now carries its own declaration file (the browser init's return
type differs from the node facade), and a failed init terminates the worker
it just spawned before rethrowing instead of leaving it running.

* [AI] api: trim code comments to the essentials

* [AI] api: always terminate the worker when browser shutdown fails

Review feedback: a rejected close-budget left the worker running. Terminate
in a finally block so cleanup is guaranteed while the failure still reaches
the caller.

* [AI] docs: document experimental browser support in the api package

* [AI] docs: drop the CORS note from the api browser section

* [AI] docs: trim the api browser section to the basics

* [AI] api: drop the import comment in methods.ts

* [AI] Run API browser test on depot runner

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [AI] Align api vite-plugin-node-polyfills to 0.28.0

The api workspace was pinned to ^0.27.0 (left over from an earlier merge
conflict resolution) while loot-core uses ^0.28.0. This both tripped the
workspace version-consistency constraint and broke the browser worker build:
under vite 8.0.16 the 0.27 process shim no longer round-trips runtime writes
to process.env.PUBLIC_URL, so sql-wasm.wasm was fetched from
/dist/undefinedsql-wasm.wasm (404) and api.init() failed in the browser e2e.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 06:32:26 +00:00
Matt Fiddaman
62cc91d68a move publish jobs back to github runners (#8263)
* move publish jobs back to github runners

* note

* Update upcoming-release-notes/github-runners-publish.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* comments

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-06-18 19:31:20 +00:00
Matiss Janis Aboltins
2c5f8cc4ba [AI] Migrate remaining CI workflows to Depot action runners (#8254)
* [AI] Migrate remaining workflows to depot action runners

Switch all remaining GitHub-hosted runners over to their depot
equivalents:

- ubuntu-latest -> depot-ubuntu-latest in the VRT-related jobs
  (e2e-test vrt/merge-vrt, e2e-vrt-comment, vrt-update-generate,
  vrt-update-apply)
- windows-2022/windows-latest -> depot-windows-2022 in the electron
  build matrices (electron-pr, electron-master, publish-nightly-electron)
  and publish-microsoft-store

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013dQEH47R5kTkPCvhC2cpoB

* [AI] Add release note for depot runner migration

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013dQEH47R5kTkPCvhC2cpoB

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-17 20:45:11 +00:00
Matiss Janis Aboltins
3e38879e9e [AI] Add Dependency Review scan on pull requests (#8251)
* [AI] Add Dependency Review scan on pull requests

Adds a Dependency Review workflow that runs on every pull request and
fails the check when a PR introduces a dependency with a known high or
critical severity vulnerability. A summary comment is posted on failure.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012JdxWJL3mUMVSJuyDakVRZ

* [AI] Scope Dependency Review to lockfile changes, drop PR comment

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012JdxWJL3mUMVSJuyDakVRZ

* [AI] Post Dependency Review summary comment on lockfile PRs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012JdxWJL3mUMVSJuyDakVRZ

* [AI] Lower Dependency Review threshold to moderate severity

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012JdxWJL3mUMVSJuyDakVRZ

* [AI] Shorten Dependency Review release note

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012JdxWJL3mUMVSJuyDakVRZ

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-17 20:44:54 +00:00
Matiss Janis Aboltins
e5747b2f2a [AI] Replace archived check-spelling action with typos for docs spell-check (#8249)
* [AI] Replace archived check-spelling action with typos for docs spell-check

The check-spelling/check-spelling action was archived upstream and shipped a
self-disabling "secpoll" kill-switch after a maintainer-account compromise
(2026-06-16), causing the Check Spelling (Docs) workflow to fail fatally with
a security-advisory error. There is no patched release to bump to.

Replace it with crate-ci/typos, which is actively maintained and runs entirely
from the checked-out tree (no PR-comment or bot-apply machinery, so the workflow
only needs contents: read):

- Rewrite .github/workflows/docs-spelling.yml to run crate-ci/typos, dropping
  the check-spelling comment/apply jobs and the pull_request_target trigger.
- Replace the check-spelling config files with typos.toml: scope to
  packages/docs, exclude auto-generated release notes and binary assets, and
  allowlist words typos otherwise mis-flags (HSA, Lage/lage, BA).
- Fix genuine typos surfaced in current docs (schedules.md, paying-in-full.md).
- Update the contributing guide and docs-writing skill to describe the new
  allowlist location.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DstzjPjGYdWMCG4jsrH6a1

* [AI] Add docs-spelling release note and format README

Fix the remaining CI checks on the spell-check migration:

- Add upcoming-release-notes/8249.md (Maintenance) so the "Release notes"
  check passes.
- Reformat .github/actions/docs-spelling/README.md with oxfmt so the lint
  ("Test") and autofix.ci checks pass (autofix.ci is not permitted to modify
  files under .github, so the formatting has to be committed directly).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DstzjPjGYdWMCG4jsrH6a1

* [AI] Disable credential persistence in docs-spelling checkout

Address the code-scanning (zizmor) and CodeRabbit review finding: the
read-only spell-check job performs no authenticated git operations, so set
persist-credentials: false on actions/checkout as a hardening measure.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DstzjPjGYdWMCG4jsrH6a1

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-17 19:19:13 +00:00
Matiss Janis Aboltins
bba89d1fd8 [AI] Migrate CI workflows to Depot-managed runners (#8205)
* [AI] Migrate CI workflows to Depot-managed runners

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [AI] Rename release notes to match PR number

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [AI] Empty commit to trigger CI

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [AI] Keep VRT jobs on GitHub-hosted runners

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [AI] Use 4-vCPU Depot Windows runners for Electron builds

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [AI] Use 4-vCPU Depot Ubuntu runners for Electron builds

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [AI] Use 4-vCPU Depot runners for functional e2e tests

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [AI] Scale Electron build runners to 8 vCPUs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [AI] Scale Ubuntu Electron builds to 4 vCPUs and move Windows builds back to GitHub runners

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [AI] Move Microsoft Store publish back to GitHub Windows runner

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [AI] Add actionlint config for Depot runner labels

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>
2026-06-17 07:36:33 +00:00
Michael Clark
3f86f2785f :electron: Fix desktop app workflow for windows builds (#8211)
* fix desktop app workflow for windows builds

* release notes

* append variable to github env so its available in other steps

* pin to 2022

* release notes
2026-06-13 21:12:46 +00:00
Matiss Janis Aboltins
ecbdea2e22 [AI] Skip release notes check for Dependabot PRs (#8185)
Dependabot never adds a file under upcoming-release-notes/, so the
check-release-notes job always failed on its PRs. Skip the check when
the PR author is dependabot[bot].

https://claude.ai/code/session_014oT7jczAkGT8RSwJYpPBur

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-11 17:02:18 +00:00
Matiss Janis Aboltins
27c6ded5a9 [AI] Drop ACTIONS_UPDATE_TOKEN from release workflows (#8142)
* [AI] Drop ACTIONS_UPDATE_TOKEN from release workflows

Replace the implicit push-triggers-workflow link (which relied on the ACTIONS_UPDATE_TOKEN PAT) with an explicit workflow_run chain from "Cut release branch" to "Release notes", falling back to the built-in GITHUB_TOKEN. The PAT stays in vrt-update-apply.yml, which genuinely needs it to push to contributor forks and re-trigger their PR CI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] Add release note for ACTIONS_UPDATE_TOKEN removal

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Update 8142.md

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 20:52:44 +00:00
Matiss Janis Aboltins
ca31154ef4 [AI] update contributor guidelines for AI usage (#8135)
* [AI] Surface anti-slop and self-review expectations at PR time

Drive-by, LLM-generated PRs (often many at once from one author) burn
maintainer review time. The repo's AI usage policy already covers this,
but contributors never see it in the PR flow.

- Strengthen the fork-PR welcome comment to ask for a human self-review
  confirmation, a plain-language testing note, and AI disclosure, plus a
  note discouraging opening many PRs at once.
- Add a "Quality Over Quantity" section to the AI usage policy naming the
  volume pattern and its consequences.
- Add an AI-disclosure prompt and tighten the self-review item in the PR
  template.

No mechanical CI gates on PR body content: those are trivially satisfied
by the same tools that generate the slop, so the change relies on human
accountability and a linkable policy instead.

* [AI] Point welcome comment at the PR template instead of inline asks

Replace the three "reply on this PR with" bullets with a single checklist
item asking contributors to use the PR template and fill in its checkboxes,
keeping the welcome comment short.

* [AI] Add AI disclosure checklist item to fork PR welcome comment

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-07 16:35:44 +00:00
Matiss Janis Aboltins
44868bd8cd [AI] Enable "do not merge" check on merge queue events (#8092)
* [AI] Run do-not-merge check on merge_group events

The block-do-not-merge workflow only triggered on pull_request events, so
it never ran in the merge queue and could not be made a required check.
Adding the merge_group trigger lets the job run and pass in the queue
context (where pull_request labels are absent), allowing it to be required.

* [AI] Add release notes for merge queue do-not-merge fix

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-04 22:05:37 +00:00
Matiss Janis Aboltins
a8547d4f30 Remove environment from release notes workflow (#8091)
* Remove environment from release notes workflow

Removed the environment specification from the release notes workflow.

* Update release-notes CI job configuration

Removed the unnecessary 'environment' from the release-notes CI job.
2026-06-04 21:41:52 +00:00
Matiss Janis Aboltins
e207d19183 [AI] Add GitHub workflow to block PRs with "do not merge" label (#8090)
* [AI] Add CI job that fails when 'do not merge' label is set

* [AI] Rename do not merge check job to "Block PRs with do not merge label"

* [AI] Rename do not merge workflow to "Block PRs with do not merge label"

* [AI] Add release notes for do not merge CI check

* Update 8090.md

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-04 21:08:35 +00:00
Matiss Janis Aboltins
ab35bd633b [AI] Remove AI-generated release notes workflow and support custom filenames (#7963)
* [AI] Relax release-notes filename convention

Allow descriptive filenames (e.g. add-payee-autocomplete.md) for
upcoming release notes instead of requiring {PR_NUMBER}.md.

The PR number was only used to build the [#1234](.../pull/1234) link in
the generated changelog. The generation script now resolves the PR per
file by finding the commit that added it (git log --diff-filter=A
--follow) and querying GitHub's commits/{sha}/pulls endpoint. Numeric
filenames remain valid via a fast path.

Also retires the CodeRabbit/OpenAI-triggered auto-creator workflow,
which existed to guess summaries and stamp the PR-numbered filename;
neither is needed once contributors can pick a slug up front.

* Add release notes for PR #7963

* [AI] Use execFile to look up release-note add-commits

resolvePrNumber() interpolated a path from fs.readdir into a shell-
evaluated `git log` command. Switch to execFile with an argv array so
filenames containing shell metacharacters can't break out of the
intended command.

* [AI] Drop duplicate release note added by the to-be-removed auto-creator

The CodeRabbit-triggered workflow ran one last time from master before
this PR removes it, and committed upcoming-release-notes/7963.md
duplicating the existing relax-release-notes-filenames.md entry. Keep
the slug-named note since it exercises the new flexible-filename code
introduced in this PR.

* [AI] Don't fail release-notes generation on transient API errors

fetchPrForCommit() handled non-OK HTTP responses but let fetch() and
res.json() exceptions propagate, so a single network blip or malformed
response would abort the whole release-notes generation. Wrap them in a
try/catch that logs and returns null, matching the pattern already used
in resolvePrNumber for execFile errors.

* [AI] Address CodeRabbit full-review nits

- bin/release-note-generator.ts: tighten slug regex to reject trailing
  and consecutive dashes (matching slugify output), and make slugify
  fall back to "untitled" so an all-non-alphanumeric input can't
  produce a hidden ".md" filename.
- packages/ci-actions/bin/release-notes-check.mjs: switch to execFile
  for git fetch/diff, matching release-notes-generate.mjs and removing
  shell interpolation of BASE_REF.
- packages/ci-actions/bin/release-notes-generate.mjs: explicitly check
  GITHUB_REPOSITORY before splitting, consistent with the other env
  var guards a few lines below.
- upcoming-release-notes/relax-release-notes-filenames.md: fix author
  casing (matiss -> MatissJanis) so changelog attribution is correct.

* [AI] Reject empty release-note bodies

content.trim().split('\n').length === 1 is true for the empty string
(''.split('\n') returns [''] of length 1), so blank notes slipped past
the single-line check. Reject empty trimmed content explicitly.

* [AI] Resolve PR numbers from commit subjects instead of GitHub's API

parseReleaseNotes was doing one GitHub API round-trip per non-numeric
release-note file. That scales badly for release generation, and the
docs site's generate-upcoming-release-notes.mjs runs on every docs
build — so contributors were hitting the GitHub API (or failing 401
without a token) every time they previewed docs locally.

actualbudget squash-merges every PR through the GitHub UI, which
appends "(#NNNN)" to the resulting commit subject. So:

  git log -1 --format=%s -- <path>

plus a /\(#(\d+)\)\s*$/ match recovers the PR number without touching
the network, and works offline / without a GITHUB_TOKEN.

Side effect: switched from "first commit that added this file" to
"most recent commit touching this file", which is what we actually
want — when a file is renamed (e.g. 7907.md -> 7954.md when a wrong
PR number is corrected), the changelog should point at the rename PR,
not the original add. The SHA->PR cache and fetchPrForCommit go away;
no longer needed.

If a file's subject doesn't match (direct push to master, manually
rewritten subject), the entry still emits without a PR-link prefix —
same graceful degradation as before.

* [AI] Pin PR-number lookup to each note's add commit

resolvePrNumber was using git log -1 with no diff filter, returning
the latest commit that touched the file. That's fine until someone
edits an existing release note in a follow-up PR (typo fix, author
correction) — at which point the changelog entry would suddenly
point at the wrong PR.

Add --diff-filter=A so the lookup pins to the commit that originally
added the path. Empirically verified against this repo: renames keep
working (git records a rename as A at the new path when --follow
isn't used), and the edit case now correctly returns the original
add commit instead of the most recent touch.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-04 21:01:19 +00:00
Matt Fiddaman
bab555a117 ♻️ remove unnecessary playwright container pulls to speed up CI (#8067)
* don't use playwright where it's not needed

* note
2026-06-03 20:37:16 +00:00
Matiss Janis Aboltins
5565236ba7 [AI] Fix last zizmor issues (#7975)
* [AI] Address zizmor findings on workflows

Replace actions-ecosystem/action-add-labels and action-remove-labels
with `gh` CLI calls (superfluous-actions). Silence the six
dangerous-triggers findings on pull_request_target/workflow_run
workflows with inline `# zizmor: ignore[dangerous-triggers]` and a
short rationale — each workflow already follows GitHub's documented
safe pattern (no PR code checkout, or validated artifacts only).

* [AI] Add release note for zizmor workflow fixes

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-28 07:31:45 +00:00
Michael Clark
fd9d2c3bf4 🔧 Prevent release branch workflow from running on forks (#7949)
* prevent release branch worfklow from running on forks

* release notes
2026-05-25 20:10:50 +00:00
Matt Fiddaman
bef27433b8 fix zizmor issues with release workflows (#7908)
* fix zizmor issues with release workflows

* note
2026-05-19 21:42:47 +00:00
Matt Fiddaman
f36189d027 fix docker nightly tag naming (#7901)
* fix nightly tag naming

* note
2026-05-19 17:10:05 +00:00
Matt Fiddaman
ed929cff22 docker edge -> nightly (#7898)
* edge -> nightly

* note

* Apply suggestions from code review

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-05-19 15:45:30 +00:00
Matt Fiddaman
ecfe43fdda split release into two branches (#7844)
* split release into two branches

* update docs to match the new process

* note

* zizmor comment

* Update check-spelling metadata

* use single long lived release branch

* coderabbit

* jfdoming suggestions
2026-05-19 12:47:08 +00:00
Matiss Janis Aboltins
1f101077d6 [AI] zizmor: add environment references to secret-consuming workflows (#7856)
* [AI] Reference dedicated environments for workflows using secrets

Assigns each secret-consuming workflow to a dedicated GitHub
environment so zizmor's secrets-without-environment audit passes:

- ai-generated-release-notes.yml -> ai-release-notes
- docs-spelling.yml (update job) -> docs-spelling
- i18n-string-extract-master.yml -> i18n
- release-notes.yml -> pr-automation
- vrt-update-apply.yml -> pr-automation

* [AI] Rename release notes file to match PR #7856

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-15 21:45:12 +00:00
Matiss Janis Aboltins
3d47eae87b [AI] Replace GitHub Actions with native gh CLI commands (#7852)
* [AI] Replace superfluous actions flagged by zizmor

Address zizmor's `superfluous-actions` audit by replacing actions whose
functionality is already provided by the runner's pre-installed `gh` CLI:

- `actions-ecosystem/action-add-labels` -> `gh issue edit --add-label`
- `peter-evans/create-or-update-comment` -> `gh issue comment`
- `softprops/action-gh-release` -> `gh release create` / `gh release upload`

For the Electron release workflow, the create step is race-safe across
the three matrix OS jobs that share the same draft release.

* [AI] Simplify electron release upload script

- Drop the `gh release view` existence check; `gh release create ... || true`
  already handles the matrix-job race against the same draft release.
- Use `extglob` to exclude `Actual-windows.exe` inline instead of looping
  over `.exe` separately.

* Add release notes for PR #7852

* [AI] Narrow error suppression on gh release create

Only swallow the "already_exists" error from the parallel-matrix race;
propagate any other failure (auth, network, API) instead of masking it.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-15 19:51:40 +00:00
Matt Fiddaman
36e5cb17f5 fix healthcheck script (#7840)
* fix healthcheck script

* note

* test release docker image
2026-05-14 21:39:10 +00:00
Matiss Janis Aboltins
872a40f829 Add explicit permissions to GitHub Actions workflows (#7846)
* [AI] Add explicit permissions blocks to GitHub Actions workflows

Resolves zizmor "excessive-permissions" findings by declaring minimal
`permissions:` blocks for workflows that previously relied on the default
GITHUB_TOKEN permissions.

https://claude.ai/code/session_01FsyCaLEqb3C4egMPUoAFRg

* Add release notes for PR #7846

* Update category for release notes

Changed category from Enhancements to Maintenance.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-14 20:17:50 +00:00
Matiss Janis Aboltins
fd01bd855c [AI] Stabilize size-compare job by pinning downloads to run_id (#7780)
* [AI] Stabilize size-compare job by pinning downloads to run_id

The compare job in .github/workflows/size-compare.yml was flaky because
fountainhead/action-wait-for-check matched a check by name from any run
on the branch, while dawidd6/action-download-artifact with branch:/pr:
filters and workflow_conclusion: '' resolved to the latest run regardless
of completion. When a new master build started in the seconds between
waiting and downloading, the action picked up the in-progress run and
failed with "artifact not found".

Replaces the eight wait-for-check steps with one actions/github-script
step that polls listWorkflowRuns for a successful build.yml run on
master and the PR head SHA in parallel via Promise.all, then pins all
eight downloads to those run_ids.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add release notes for PR #7780

* Change category to Maintenance in release notes

Updated category from 'Enhancements' to 'Maintenance'.

* [AI] Clean up comment to remove reference to previous implementation

Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>
2026-05-14 19:41:13 +00:00
Julian Dominguez-Schatz
d3e7c1ee87 Fix some issues caught by zizmor (#7826)
* Fix some issues caught by zizmor

* Add release notes

* Add more cache ignores

* Add comments on reasoning
2026-05-13 13:19:16 +00:00
Matiss Janis Aboltins
b61732e20e [AI] Add workflow to auto-label AI-generated PRs (#7817)
* [AI] Add workflow to label '[AI]'-prefixed PRs as 'AI generated'

https://claude.ai/code/session_018yp3BsEq1CyPcw8t57nLVu

* [AI] Suppress zizmor dangerous-triggers finding and add release note

https://claude.ai/code/session_018yp3BsEq1CyPcw8t57nLVu

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-13 05:17:11 +00:00
Matiss Janis Aboltins
83073b3ee0 [AI] automated publishing workflow for crdt package (#7805)
* [AI] Require @actual-app/crdt version bump and auto-publish

Adds two workflows:
- crdt-version-check: fails PRs that modify files in packages/crdt/
  without bumping the version in packages/crdt/package.json.
- publish-crdt: publishes @actual-app/crdt to npm when the version in
  packages/crdt/package.json changes on master, tagging the release as
  crdt-v<version>.

* [AI] Skip git tagging in @actual-app/crdt publish workflow

Remove the tag-and-push step and the now-unused version output;
downgrade contents permission to read.

* [AI] Simplify crdt version-bump workflows

- Drop the redundant explicit base-branch fetch (fetch-depth: 0 already
  retrieves all remote branches).
- Remove the unreachable "no changes" guard; the pull_request paths
  filter already scopes the workflow to packages/crdt changes.
- Replace the embedded Node semver comparison with `sort -V`.
- Read versions with `jq` instead of inline Node.

* [AI] Add release notes for crdt publish workflows

* [AI] Restrict GITHUB_TOKEN permissions in crdt workflows

Add top-level `permissions: contents: read` to both crdt workflows so
the implicit jobs no longer inherit overly broad permissions (flagged by
zizmor).

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-12 21:23:47 +00:00
Matiss Janis Aboltins
daa698e7d2 [AI] Fix /update-vrt merge step when only one shard has changes (#7802)
The Merge VRT Patches job collects shard patches with the glob
`/tmp/shard-patches/*/vrt-shard.patch`, which assumes every downloaded
artifact lands in its own `path/<artifact-name>/` subdirectory. But
actions/download-artifact only does that when 2+ artifacts match the
pattern; when exactly one matches it unpacks the artifact directly into
`path`. So whenever a `/update-vrt` run touches snapshots in a single
shard (the common case) the patch ends up at
`/tmp/shard-patches/vrt-shard.patch`, the glob matches nothing, and the
job reports "No shard patches to merge" despite a patch having been
generated (e.g. run 25679233565).

Replace the glob with a recursive `find` so the patches are located
under either layout. `merge-multiple: true` is not an option here
because every shard artifact contains a file literally named
`vrt-shard.patch` and they would overwrite each other.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 20:38:27 +00:00
Matiss Janis Aboltins
82673ecd50 [AI] Use bash for /update-vrt merge step (#7783)
The Merge VRT Patches job runs inside the Playwright container where
the default GitHub Actions shell is `sh -e {0}`, not bash. The merge
step uses bash-only constructs (`shopt -s nullglob`, array literals,
`${#patches[@]}`, `"${patches[@]}"`), so every /update-vrt run that
reaches the merge stage now exits 127 with `shopt: not found` (e.g.
run 25609625260).

Pin this step to `shell: bash` to match the explicit `shell: bash` we
already use elsewhere in the workflow. The sibling shard-patch creation
steps stay on the default sh because they only use POSIX features.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 18:56:50 +00:00
Michael Clark
b05c207123 :electron: Publish to Microsoft store after release is published (#7757)
* move desktop app microsoft store publish to after the release is published

* release notes
2026-05-09 21:16:13 +00:00
Matiss Janis Aboltins
b9ab3e7bc6 [AI] Fix /update-vrt build step after lage browser-build refactor (#7781)
The build-web job in vrt-update-generate.yml invoked
`yarn workspace @actual-app/core build:browser`, but #7602 removed that
script when it routed the browser pipeline through
`lage build:browser --to=@actual-app/web` (orchestrated by
bin/package-browser). The recent /update-vrt parallelization (#7641)
preserved the now-stale per-workspace invocations, so every comment
trigger fails with "Couldn't find a script named build:browser".

Match the working e2e-test.yml build-web step exactly:
`yarn build:browser --skip-translations`. lage's `^build` edge handles
the upstream graph (crdt, plugins-service, loot-core) automatically, and
`--skip-translations` keeps the captured snapshots aligned with regular
VRT runs (which also strip Weblate locale chunks for determinism).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 18:16:42 +00:00
Matiss Janis Aboltins
3104503a8a Refactor VRT workflow to parallelize browser and desktop tests (#7641)
* [AI] Parallelize and shard /update-vrt workflow

Mirror the pre-built bundle + 3-way sharding pattern that #7503 applied
to e2e-test.yml, plus split desktop VRT into its own job so it runs
concurrently with the browser passes instead of sequentially on the
same runner.

- New `build-web` job compiles the browser bundle once and uploads it
  as an artifact (REACT_APP_NETLIFY=true so the "Create test file"
  button survives tree-shaking).
- `browser-vrt` runs as a 3-shard matrix, each downloading the prebuilt
  artifact and using `E2E_USE_BUILD=1` so `serve-build.mjs` replaces
  per-shard Vite startup.
- `desktop-vrt` runs in parallel with the browser shards.
- Each shard produces its own PNG-only `git format-patch` and
  validates it before upload; `merge-patch` re-validates and applies
  every shard patch to produce the single `vrt-patch-<pr>` artifact
  that `vrt-update-apply.yml` already consumes unchanged.
- Keeps `permissions: contents: read, pull-requests: read`,
  `persist-credentials: false` on every checkout, and env-indirection
  for fork-controlled values (zizmor-friendly).

Expected wall-clock drop from ~50 min to ~15-20 min.

* Add release notes for PR #7641

* [AI] Fix vacuous PNG-only patch validation regex

`git format-patch` emits a `GIT binary patch` block for PNGs and does
not produce `+++ b/foo.png` / `--- a/foo.png` text-diff headers. The
existing validation `grep -E '^(\+\+\+|---) [ab]/' patch | grep -v
'\.png$'` therefore matches zero lines for any legitimate PNG-only
patch, and the guard passes vacuously — meaning a crafted binary patch
naming a non-PNG file would also pass undetected.

Match `diff --git` headers instead. Those are present for both text
and binary patches, and naming both source and destination paths gives
us a clean `^diff --git a/<path>.png b/<path>.png$` shape to enforce.

Updated all four validation points in vrt-update-generate.yml (per
shard, in the merge-patch re-validation loop, and on the final merged
patch) plus the pre-existing third defense layer in
vrt-update-apply.yml. Also fixed FILES_CHANGED counter in apply
workflow since it relied on the same broken `+++` pattern.

Verified the new regex with binary patches: legit PNG-only ACCEPTED,
single non-PNG REJECTED, mixed PNG+non-PNG REJECTED.

Reported by CodeRabbit on PR #7641.

* [AI] Move workspace-trust step before setup in browser-vrt and desktop-vrt

Master's #7699 moved the safe.directory git config to a separate step
that runs before the setup composite action, because the setup action
performs git operations (yarn --immutable + checkout of the
translations repo) that fail when the workspace isn't trusted in
container environments.

The merge resolution kept the trust step before setup in build-web (as
master had it) but left the trust step after setup in the new
browser-vrt and desktop-vrt jobs. They have the same setup composite
and would hit the same failure mode — apply the same fix.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>
2026-05-09 14:26:21 +00:00
Matiss Janis Aboltins
8ab8277429 [AI] Replace Support contact link with auto-closing tech-support issue template (#7670)
* [AI] Replace Support contact link with auto-closing tech-support issue template

Convert the external Discord "Support" contact link into a proper GitHub issue
form so users who skip the redirect still land somewhere useful. The new form
has a single "Describe your problem" field and a prominent notice that tech
support tickets are auto-closed and Discord is the place to get help. A new
workflow watches for the `tech-support` label, posts a friendly Discord pointer
and closes the issue, mirroring the existing feature-request auto-close flow.

* Add release notes for PR #7670

* [AI] Replace create-or-update-comment action with gh CLI

The peter-evans/create-or-update-comment action is unnecessary since GitHub's gh CLI (pre-installed on all GitHub-hosted runners) provides the same functionality natively via 'gh issue comment' and 'gh issue close' commands. This change addresses the zizmor security scanner warning about using an action when the functionality is already included by the runner.

Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>

* Update 7670.md

* [AI] Fix formatting in workflow file

Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>

* Update issues-close-tech-support.yml

Co-authored-by: Stephen Brown II <Stephen.Brown2@gmail.com>

* Update tech-support.yml

Co-authored-by: Stephen Brown II <Stephen.Brown2@gmail.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>
Co-authored-by: Stephen Brown II <Stephen.Brown2@gmail.com>
2026-05-08 20:24:17 +00:00
Matiss Janis Aboltins
e3b42b51a3 [AI] Fix publish-npm-packages workflow setup-node input (#7755)
* [AI] Fix publish-npm-packages workflow setup-node input

The `cache` input on actions/setup-node expects a package-manager
string ('npm'/'yarn'/'pnpm'), not a boolean. Passing `cache: false`
caused the publish job on the v26.5.1 release to fail with
"Caching for 'false' is not supported". Caching is off by default,
so the input is removed entirely.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add release notes for PR #7755

* Change category from Bugfixes to Maintenance

Fix npm dependency caching in the publish workflow by removing the cache disabling setting.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-08 18:31:39 +00:00
Michael Clark
1f4f706c4a ⚙️ Updating workflow based on audit (#7740)
* updating workflows with audit feedback

* release notes
2026-05-07 20:26:12 +00:00
Matt Fiddaman
263358b5cf fix vrt update workflow (#7699)
* fix vrt update workflow

* note
2026-05-05 20:26:48 +00:00
Matiss Janis Aboltins
ff0f5bdb35 [AI] lage - move browser build to using lage (#7602)
* Simplify desktop client browser build

* [AI] Move browser build orchestration into vite config and lage

Moves loot-core worker build, public/ staging (migrations, default-db,
sql-wasm, data-file-index), and build-stats wiring from the deleted
packages/desktop-client/bin/build-browser shell script into a
lootCoreBackend vite plugin in packages/desktop-client/vite.config.mts.

Adds a build:browser target to lage.config.js so bin/package-browser
runs as a single `lage build:browser --to=@actual-app/web` call, with
crdt + loot-core built via lage's ^build dependency before the
desktop-client build.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Refactor e2e-test workflow and update desktop-client configurations

* [AI] Move plugins-service staging into desktop-client vite config

Declares plugins-service as a workspace devDependency of @actual-app/web
so lage's ^build edge picks it up automatically in the build:browser
pipeline, and moves the cross-package file staging (production copy +
dev serving) into vite.config.mts, mirroring the lootCoreBackend
pattern. Drops the plugins-service shell wrapper script and simplifies
its package.json scripts to invoke vite build directly. Updates root
start:browser to run plugins-service watch in parallel with the dev
server instead of pre-building once.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Sync tsconfig project references for plugins-service edge

Follow-up to the plugins-service workspace edge: adds the
../plugins-service project reference in packages/desktop-client/tsconfig.json
via yarn sync:tsconfig-references.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Release notes

* [AI] Ignore .venv/ so lage's git hasher skips Electron CI's Python venv

Electron CI provisions a Python virtualenv at the repo root for
setuptools. With browser builds now routed through lage, lage's
git hash-object pass walks untracked-not-ignored files and fails on
the venv's broken lib64 symlink ("fatal: Unable to hash .../.venv/lib64").

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Bake Weblate translations back into VRT/e2e bundle

build-web set download-translations: false and relied on bin/package-browser's
ad-hoc git clone + git pull. That path is fragile inside the playwright
container, so vite's import.meta.glob('/locale/*.json') frequently produced an
empty languages map and the bundle shipped with no en.json. VRTs then rendered
source-code English and diffed against snapshots authored from Weblate strings.

Route translation provisioning back through actions/checkout (download-translations: true)
in build-web and vrt-update-generate, and add --skip-translations to bin/package-browser
(mirroring bin/package-electron) so the in-script git pull is bypassed when CI
has already staged the locale dir.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Skip translation cloning in build-web bundle for VRT determinism

bin/package-browser used to unconditionally clone actualbudget/translations
before vite ran, baking Weblate en.json into the build artifact. With the
e2e-test pipeline now serving that artifact via serve-build.mjs, VRT
screenshots ended up rendering Weblate strings — drifting from the snapshots,
which were authored against source-code English (master VRTs ran on vite dev
without a locale dir).

Pass --skip-translations to bin/package-browser from build-web so the bundle
ships with no locale chunks. download-translations stays 'false' across the
e2e-test and vrt-update-generate workflows, matching the prior behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 20:20:13 +00:00
Matiss Janis Aboltins
aeb28d3b87 Add Discord notification for nightly theme catalog scan failures (#7595)
* [AI] Notify Discord when nightly theme catalog scan fails

Adds an if: failure() step to the validate-theme-catalog job that posts a
minimal alert to the DISCORD_WEBHOOK_URL webhook with a link back to the
failing workflow run. Fires on both theme validation failures (script exits
1) and earlier step failures (checkout/setup), so infrastructure breakage
is also surfaced. nofail: true keeps a Discord outage from cascading into
a red job.

* [AI] Drop setup comment from Discord notify step

* [AI] Move Discord notify to its own job gated by an environment

Splits the notify step into a separate notify-failure job that depends on
validate-theme-catalog and runs only on failure. The new job binds to the
nightly-alerts GitHub Environment so the DISCORD_WEBHOOK_URL secret is
scoped to a dedicated environment rather than inherited at the repo level
(zizmor secrets-without-environment).

* [AI] Add release notes for 7595

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-23 06:58:21 +00:00
Copilot
1c97388654 [AI] Consolidate npm release and nightly publishing into one workflow (#7583)
* [AI] Unify npm release and nightly publish workflows

Agent-Logs-Url: https://github.com/actualbudget/actual/sessions/3f8de051-a9a7-4527-88d8-5c44bc06a562

Co-authored-by: jfdoming <9922514+jfdoming@users.noreply.github.com>

* [AI] Harden unified npm publish workflow conditionals

Agent-Logs-Url: https://github.com/actualbudget/actual/sessions/3f8de051-a9a7-4527-88d8-5c44bc06a562

Co-authored-by: jfdoming <9922514+jfdoming@users.noreply.github.com>

* [AI] Clarify nightly install step and add concise release note

Agent-Logs-Url: https://github.com/actualbudget/actual/sessions/af3d68aa-d217-47be-addb-1b40b08f533b

Co-authored-by: jfdoming <9922514+jfdoming@users.noreply.github.com>

* [AI] Revert release note edit and make npm publish workflow ACT-compatible (#7584)

* Initial plan

* [AI] Revert release note edit and validate workflow with act

Agent-Logs-Url: https://github.com/actualbudget/actual/sessions/df98a192-197a-4df4-a804-80b69116f742

Co-authored-by: jfdoming <9922514+jfdoming@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jfdoming <9922514+jfdoming@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jfdoming <9922514+jfdoming@users.noreply.github.com>
2026-04-22 15:18:29 +00:00
Julian Dominguez-Schatz
8323a7d27c Reduce permissions in stale workflow (#7555)
* Restrict permissions on stale workflow

* Add release notes for reducing permissions in stale workflow
2026-04-22 15:17:35 +00:00
Matiss Janis Aboltins
846b6a6b7a [AI] Add nightly CI scan for custom theme catalog (#7566)
* [AI] Add nightly CI scan for custom theme catalog

Adds a scheduled GitHub Actions workflow that fetches `actual.css` from
every repo in `customThemeCatalog.json` and runs it through the same
`embedThemeFonts` + `validateThemeCss` pipeline the app uses at install
time. Failing themes fail the job so maintainers get an alert when a
third-party repo introduces a regression.

The scan treats fetched CSS as opaque text: never executed, never
injected into a DOM, size-capped at 512 KB per file, 15s per fetch,
restricted to raw.githubusercontent.com with redirects disabled, and
run with `contents: read` permissions only. Each catalog `repo` is
schema-checked against `owner/repo` before being interpolated into
the URL.

* [AI] Simplify theme catalog scan

- Reuse `CatalogTheme` type from customThemes instead of duplicating as
  `CatalogEntry` in the script.
- Hoist `appendFileSync` to the static `node:fs` import; drop the dynamic
  import inside `writeStepSummary`.
- Drop the narrative header docstring and the trailing `// ...` comments
  that just restated constant names.
- Drop the redundant URL-prefix re-check inside the CSS fetch helper;
  the single call site constructs the URL from a pinned literal.
- Drop the 250 ms inter-request delay (GitHub Raw rate limits are not
  relevant for 21 requests, and the trailing delay was idle wall-clock
  against the 10-min job budget).
- Give each font fetch inside `embedThemeFonts` its own 15 s timeout
  via `AbortSignal.any`, instead of sharing one signal across every
  font in a theme. Drop the now-unnecessary caller-supplied signal
  from the CI call site.

* [AI] Fix lint on theme catalog scan imports
2026-04-21 21:18:21 +00:00
Julian Dominguez-Schatz
07c71154c9 Enable trusted publishing for releases (#7579)
* Enable trusted publishing for releases

* Add release notes for PR #7579

* Update 7579.md

* [autofix.ci] apply automated fixes

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-21 18:34:38 +00:00
Matiss Janis Aboltins
362d8d60e4 [AI] Optimize CI e2e tests with pre-built bundle serving (#7503)
* [AI] Speed up and stabilize Playwright e2e tests

- Serve the prebuilt browser bundle via bin/serve-build.mjs in CI to
  skip per-shard Vite startup; 3-shard matrix with 4 workers each.
- Disable CSS animations in non-VRT runs via a fixture-level init
  script; bump expect timeout to 10s for AutoSizer-bound assertions.
- Use page.evaluate() for React Aria button clicks and a native value
  setter + single input event for controlled-input fills to eliminate
  React Aria re-render races in createAccount and Payee/Category
  autocompletes.
- Click the matching option directly (instead of Enter on a not-yet-
  highlighted list) in mobile transaction and schedule autocompletes.
- FocusableAmountInput.applyText reads the DOM input value so the
  typed amount survives a blur that fires before React flushes the
  onChange state update under CPU contention.
- MobileTransactionEntryPage.fillAmount waits for the outer display
  button (reads parent props.value) so async rules-run completes
  before the next fillField snapshots the transaction.
- MobileNavigation dispatches nav link clicks through evaluate() to
  bypass Playwright's viewport-stability check against the navbar's
  react-spring transforms.
- MobileBudgetPage summary-button lookups use locator.or().waitFor()
  instead of an isVisible() cascade.
- ConfigurationPage.startFresh/createTestFile wait for the account
  header / budget table to mount before returning.
- Workflow hardening: persist-credentials=false on all actions/checkout
  and top-level permissions: contents: read (zizmor findings).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Apply animation-disable init script to browser.newPage pages

The previous implementation extended the test-scoped `page` fixture,
but every test creates its own page via `browser.newPage()` and never
uses the fixture-provided page — so the init script was a no-op in
every test.

Move the wrap to the worker-scoped `browser` fixture: intercept
`browser.newPage` so each page created that way has `addInitScript`
applied before the caller can navigate to it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:03:56 +00:00
Julian Dominguez-Schatz
664cfdf244 Force node version 24 for trusted publishing (#7577)
* Force node version 24 for trusted publishing

* Add release notes for PR #7577

* Enable check-latest for npm setup action

* Update nightly package publishing workflow to Node.js 24

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-04-21 16:44:03 +00:00