diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..58df3b8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,55 @@ +name: CI + +on: + pull_request: + push: + branches: + - main + +permissions: + contents: read + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + checks: + name: Typecheck, lint, unit tests + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup pnpm + uses: pnpm/action-setup@v6 + with: + version: 11.0.8 + run_install: false + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 24 + cache: pnpm + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Typecheck + run: pnpm typecheck + + - name: Lint + run: pnpm lint + + - name: Unit tests + run: pnpm test:unit + + - name: Rust format check + run: cargo fmt --manifest-path src-tauri/Cargo.toml --check diff --git a/src-tauri/src/core/github/sync/push.rs b/src-tauri/src/core/github/sync/push.rs index 5371e20..209d334 100644 --- a/src-tauri/src/core/github/sync/push.rs +++ b/src-tauri/src/core/github/sync/push.rs @@ -30,7 +30,9 @@ pub fn push_all(client: &GithubClient, settings: &GithubRepoSettings) -> AppResu continue; } let path = remote_path(path); - if let Some((_content, sha)) = client.read_file(&settings.repo_owner, &settings.repo_name, &path)? { + if let Some((_content, sha)) = + client.read_file(&settings.repo_owner, &settings.repo_name, &path)? + { deleted_files.push((path, sha)); } } diff --git a/src/base/i18n/locales.test.ts b/src/base/i18n/locales.test.ts index d53f4f9..3240b23 100644 --- a/src/base/i18n/locales.test.ts +++ b/src/base/i18n/locales.test.ts @@ -77,9 +77,14 @@ describe("locales", () => { test("does not keep stale locale keys", () => { const usedKeys = usedTranslationKeys(); - const staleKeys = Object.keys(enKeys).filter( - (key) => !usedKeys.has(key) && !key.startsWith("errors."), - ); + const staleKeys = Object.keys(enKeys).filter((key) => { + if (usedKeys.has(key) || key.startsWith("errors.")) { + return false; + } + + const singularKey = key.replace(/_plural$/, ""); + return singularKey === key || !usedKeys.has(singularKey); + }); expect(staleKeys).toEqual([]); }); diff --git a/src/base/i18n/locales/en.json b/src/base/i18n/locales/en.json index 049c856..ea6e129 100644 --- a/src/base/i18n/locales/en.json +++ b/src/base/i18n/locales/en.json @@ -65,10 +65,8 @@ "skillsNeedAttention_plural": "{{count}} skills need attention", "configsNeedAttention": "{{count}} configuration needs attention", "configsNeedAttention_plural": "{{count}} configurations need attention", - "instructions": "Instructions", "missing": "Missing link", "targetBlocked": "Blocked target", - "details": "Details", "review": "Review", "fix": "Repair", "replace": "Replace", diff --git a/src/base/i18n/locales/sv.json b/src/base/i18n/locales/sv.json index 1fd0be1..8ad6a94 100644 --- a/src/base/i18n/locales/sv.json +++ b/src/base/i18n/locales/sv.json @@ -65,10 +65,8 @@ "skillsNeedAttention_plural": "{{count}} färdigheter behöver åtgärdas", "configsNeedAttention": "{{count}} konfiguration behöver åtgärdas", "configsNeedAttention_plural": "{{count}} konfigurationer behöver åtgärdas", - "instructions": "Instruktioner", "missing": "Länk saknas", "targetBlocked": "Mål blockerat", - "details": "Detaljer", "review": "Granska", "fix": "Återskapa", "replace": "Ersätt", diff --git a/src/core/link-status/components/LinkStatusNotice/LinkStatusNotice.tsx b/src/core/link-status/components/LinkStatusNotice/LinkStatusNotice.tsx index 597b817..0d7ad08 100644 --- a/src/core/link-status/components/LinkStatusNotice/LinkStatusNotice.tsx +++ b/src/core/link-status/components/LinkStatusNotice/LinkStatusNotice.tsx @@ -34,11 +34,9 @@ function LinkStatusRow({ onFix, status }: LinkStatusRowProps) {
- {t( - status.state === "blocked" - ? "sync.targetBlocked" - : "sync.missing", - )} + {status.state === "blocked" + ? t("sync.targetBlocked") + : t("sync.missing")} {status.configName}