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
76 changes: 47 additions & 29 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ jobs:
- 'scripts/e2e-suites.txt'
- 'scripts/run-e2e.sh'
- 'package.json'
- 'package-lock.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- '.github/workflows/ci.yml'

# ── Fast checks (parallel, no E2E dependency) ──────────────────────────────
Expand Down Expand Up @@ -129,11 +130,12 @@ jobs:
- name: Compute run-scoped workdir
run: echo "E2E_WORKDIR=$RUNNER_TEMP/git-files-sync-e2e/${{ github.run_id }}/${{ github.run_attempt }}/gitea" >> "$GITHUB_ENV"
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: '22'
cache: npm
- run: npm ci --ignore-scripts
node-version: '24'
cache: pnpm
- run: pnpm install --frozen-lockfile --ignore-scripts
- name: Run disposable Gitea E2E
run: scripts/run-e2e.sh --provider gitea

Expand All @@ -142,12 +144,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: '22'
cache: npm
- run: npm ci --ignore-scripts
- run: npm run lint
node-version: '24'
cache: pnpm
- run: pnpm install --frozen-lockfile --ignore-scripts
- run: pnpm run lint

unit-test:
name: CI / Unit Test (Node ${{ matrix.node-version }})
Expand All @@ -158,15 +161,16 @@ jobs:
node-version: [22, 24]
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: ${{ matrix.node-version }}
cache: npm
- run: npm ci --ignore-scripts
cache: pnpm
- run: pnpm install --frozen-lockfile --ignore-scripts
- name: Build (compatibility check)
run: npm run build
run: pnpm run build
- name: Run tests with coverage
run: npm run test -- --coverage
run: pnpm run test --coverage
- name: Upload coverage
if: matrix.node-version == 22
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
Expand All @@ -180,14 +184,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: '22'
cache: npm
- run: npm ci --ignore-scripts
- run: npm run build
node-version: '24'
cache: pnpm
- run: pnpm install --frozen-lockfile --ignore-scripts
- run: pnpm run build
# Upload the raw built artifacts (main.js/manifest/styles.css) for ad-hoc
# PR install testing on non-main branches. `npm run build` already ran
# PR install testing on non-main branches. `pnpm run build` already ran
# above as the validation (tsc -noEmit + Obsidian 1.11.0 compat typecheck +
# esbuild), so this upload is in the *same* job -- never a separate
# upload-artifact job that could drift out of sync with the build state.
Expand Down Expand Up @@ -307,16 +312,27 @@ jobs:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
if: steps.gate.outputs.run == 'true'

# The self-hosted runners share a persistent pnpm store (/cache/pnpm-store)
# across concurrent jobs. The two provider legs run in parallel and race
# while pnpm/action-setup self-switches the runner's pnpm 11 to the pinned
# 12.14.0 inside that store ("Cannot find module .../@pnpm/exe.linux-x64/
# bin/pnpm.mjs"). Give each leg its own store under RUNNER_TEMP instead.
- name: Use a job-private pnpm store
if: steps.gate.outputs.run == 'true'
run: echo "pnpm_config_store_dir=$RUNNER_TEMP/pnpm-store-${{ matrix.provider }}" >> "$GITHUB_ENV"

- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
if: steps.gate.outputs.run == 'true'
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
if: steps.gate.outputs.run == 'true'
with:
node-version: '22'
cache: npm
node-version: '24'
cache: pnpm

# --ignore-scripts: this job only needs installed deps to run vitest/the
# harness, not husky's `prepare` git-hook setup -- skipping lifecycle
# scripts avoids letting an install-time script run arbitrary code.
- run: npm ci --ignore-scripts
- run: pnpm install --frozen-lockfile --ignore-scripts
if: steps.gate.outputs.run == 'true'

# One entry point for the whole real-provider E2E flow: scripts/run-e2e.sh
Expand Down Expand Up @@ -399,12 +415,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: '22'
cache: npm
- run: npm ci --ignore-scripts
- run: npm run build
node-version: '24'
cache: pnpm
- run: pnpm install --frozen-lockfile --ignore-scripts
- run: pnpm run build
- name: Create plugin package
run: |
VERSION=$(node -p "require('./manifest.json').version")
Expand Down Expand Up @@ -451,12 +468,13 @@ jobs:
with:
fetch-depth: 0
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: '22'
cache: npm
- run: npm ci
- run: npm run build
node-version: '24'
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm run build
- name: Attest main.js
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
Expand All @@ -468,4 +486,4 @@ jobs:
subject-path: styles.css
- env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }}
run: npx semantic-release
run: pnpm exec semantic-release
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
npm run lint && npm run build
pnpm run lint && pnpm run build
10 changes: 5 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ Before writing code:
## Definition of Done

A feature is done only when all of the following hold, with evidence recorded (command + result) in `progress.md`:
- `npx eslint .` — 0 errors
- `npm run build` — passes (tsc + Obsidian 1.11.0 compat typecheck + esbuild)
- `npx vitest run` — passes
- `pnpm exec eslint .` — 0 errors
- `pnpm run build` — passes (tsc + Obsidian 1.11.0 compat typecheck + esbuild)
- `pnpm exec vitest run` — passes
- Manual verification in Obsidian, when the change has a runtime UI surface

## Stay in Scope
Expand Down Expand Up @@ -40,7 +40,7 @@ Before ending a session:

### 1. TDD & Linting (Skill: `obsidian-development`)
- **Rule**: Write Vitest tests BEFORE implementation.
- **Execution**: Offload `npx vitest run` and `npm run lint` to Haiku.
- **Execution**: Offload `pnpm exec vitest run` and `pnpm run lint` to Haiku.
- **Report Format**: `Success: N items, Failure: X items` (including error logs on failure).

### 2. Marketplace Readiness (Skill: `obsidian-marketplace-check`)
Expand All @@ -52,4 +52,4 @@ Before ending a session:
- **Failure Protocol**: Fetch and return specific error messages from the CI pipeline.

### 4. Git Integrity
- **Pre-commit**: Husky hook running `npm run lint && npm run build`.
- **Pre-commit**: Husky hook running `pnpm run lint && pnpm run build`.
12 changes: 6 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

- **Startup**: read `feature_list.json` (active/next-up work; GitHub Issues on `firstsun-dev/git-files-sync`, Project #6, is the actual source of truth — re-sync before trusting stale entries) and `progress.md` (what's open right now).
- **Before editing**: run `./init.sh` (installs deps, then lint + test + build) to confirm you're starting from a green baseline.
- **Definition of done**: `npx eslint .` has 0 errors, `npm run build` passes (includes the Obsidian 1.11.0 compat typecheck), and `npx vitest run` passes, *and* evidence of that run is recorded (one line: command + result) in `progress.md` or the PR description — not just claimed.
- **Definition of done**: `pnpm exec eslint .` has 0 errors, `pnpm run build` passes (includes the Obsidian 1.11.0 compat typecheck), and `pnpm exec vitest run` passes, *and* evidence of that run is recorded (one line: command + result) in `progress.md` or the PR description — not just claimed.
- **Scope**: work one `feature_list.json` entry at a time; don't start the next until the current one's evidence is recorded.
- **End of session**: move finished items from `progress.md` into `archive/YYYY-MM.md` (current month).
- Issue/PR conventions (Conventional Commits titles, Project #6 fields, English-only for this public plugin repo) are defined in the `firstsun-pm` skill, not duplicated here.

## Development Commands
- Build: `npm run build` (runs type check and esbuild in production mode)
- Dev: `npm run dev` (builds in watch mode using esbuild)
- Lint: `npm run lint` (runs eslint check)
- Test: `npm run test` (runs vitest suite)
- Version bump: `npm run version` (updates manifest.json and versions.json via script)
- Build: `pnpm run build` (runs type check and esbuild in production mode)
- Dev: `pnpm run dev` (builds in watch mode using esbuild)
- Lint: `pnpm run lint` (runs eslint check)
- Test: `pnpm run test` (runs vitest suite)
- Version bump: `pnpm run version` (updates manifest.json and versions.json via script)

## Architecture Contract

Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,12 @@ A practical multi-device habit is still useful: refresh before editing on anothe

```bash
git clone https://github.com/firstsun-dev/git-files-sync.git
npm install
pnpm install

npm run dev # watch build
npm run build # type-check + production build
npm run test # vitest suite
npm run lint # eslint
pnpm run dev # watch build
pnpm run build # type-check + production build
pnpm run test # vitest suite
pnpm run lint # eslint
```

## License
Expand Down
4 changes: 2 additions & 2 deletions docs/test/github-e2e-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The production service is exercised unmodified; every remote assertion goes thro

## Required secrets / config

Set on `firstsun-dev/git-files-sync` (this repo) for CI, or exported locally for `npm run test:e2e -- --provider github`:
Set on `firstsun-dev/git-files-sync` (this repo) for CI, or exported locally for `pnpm run test:e2e -- --provider github`:

| Name | Kind | Purpose |
|---|---|---|
Expand Down Expand Up @@ -81,7 +81,7 @@ Both patterns were added to the regex, with regression tests in `tests/services/

```
E2E_GITHUB_OWNER=<owner> E2E_GITHUB_REPO=<repo> E2E_GITHUB_TOKEN=<fine-grained PAT> \
npm run test:e2e -- --provider github
pnpm run test:e2e -- --provider github
```

Verified: 3 consecutive clean runs (10/10 tests) against `firstsun-dev/obsidian-sync-test` as of 2026-08-07.
8 changes: 4 additions & 4 deletions docs/testing/real-provider-e2e.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,9 @@ and workdir for debugging.
## Running locally

```sh
npm run test:e2e -- --provider gitea # no credentials needed, runs a real Gitea in Docker
npm run test:e2e -- --provider github # needs E2E_GITHUB_* below
npm run test:e2e -- --provider gitlab # needs E2E_GITLAB_* below
pnpm run test:e2e -- --provider gitea # no credentials needed, runs a real Gitea in Docker
pnpm run test:e2e -- --provider github # needs E2E_GITHUB_* below
pnpm run test:e2e -- --provider gitlab # needs E2E_GITLAB_* below
```

| Var | Required for | Notes |
Expand Down Expand Up @@ -326,7 +326,7 @@ GitHub/GitLab checks it cannot produce.
assigns its loopback host port. Concurrent runs also use separate `mktemp` workdirs. A container
left by a hard-killed local process can be removed manually (`docker rm -f <name>`).
- **`E2E_PROVIDER is not set` error**: `vitest.e2e.config.ts` refuses to run directly under
`npx vitest` — always go through `npm run test:e2e -- --provider <name>` (or the CI steps),
`npx vitest` — always go through `pnpm run test:e2e -- --provider <name>` (or the CI steps),
which set it.

## Known gaps
Expand Down
16 changes: 8 additions & 8 deletions init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ set -e

echo "=== Harness Initialization ==="

echo "=== npm install ==="
npm install
echo "=== pnpm install ==="
pnpm install --frozen-lockfile

echo "=== npm run lint ==="
npm run lint
echo "=== pnpm run lint ==="
pnpm run lint

echo "=== npm test ==="
npm test
echo "=== pnpm test ==="
pnpm test

echo "=== npm run build ==="
npm run build
echo "=== pnpm run build ==="
pnpm run build

echo "=== Verification Complete ==="
echo ""
Expand Down
Loading
Loading