Skip to content

Commit 62f4c8d

Browse files
authored
ci: enforce lint and report coverage on PRs (#119)
## What changed - **Lint in CI**: added a non-mutating `pnpm exec biome ci .` step to the `test` job (the existing `lint` script is `biome check --write`, which mutates files and is unsafe for CI). - **Coverage config**: added a `coverage` block to `vite.config.ts` mirroring codemirror-mcp — `enabled: true`, `reportOnFailure: true`, `reporter: ["text", "html", "json-summary", "json"]`, scoped to `src/**`. - **Coverage reporting**: added the SHA-pinned `davelosert/vitest-coverage-report-action@…3c50566 # v2` step (`if: always()`, `pr-number: auto`) with the same `pull-requests: write` permission codemirror-mcp uses (already present on this job). - **Mechanical lint fixes**: `biome ci .` initially failed with 3 errors (import ordering + formatting). Ran the repo's fixer (`biome check --write`) once; it reformatted `demo/index.ts`, `src/inline-edit/trigger.ts`, and `src/inline-edit/__tests__/inline-completion.test.ts` (import sort, quote style, line wrapping — no behavior change). Included here so CI passes. `@vitest/coverage-v8` was already a dev dependency at `3.2.4` (matching `vitest` 3.2.4), so no dependency/lockfile change was needed. ## Why The lint script and config already existed but CI never ran lint, and no coverage was measured at all. This makes both gates visible on every PR. ## How verified - `pnpm install --frozen-lockfile` - `pnpm exec biome ci .` — exit 0 after the mechanical fixes - `pnpm run test` — passes; `coverage/coverage-summary.json` is generated (consumed by the report action). `coverage/` is gitignored. Part of the marimo-team engineering-excellence initiative to make existing-but-unenforced quality gates actually run in CI.
1 parent 738a3d2 commit 62f4c8d

5 files changed

Lines changed: 30 additions & 11 deletions

File tree

.github/workflows/test.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,21 @@ jobs:
3535
- name: 📥 Install dependencies
3636
run: pnpm install --ignore-scripts --frozen-lockfile
3737

38+
- name: 🧹 Lint
39+
run: pnpm exec biome ci .
40+
3841
- name: 🔍 Type Check
3942
run: pnpm run typecheck
4043

4144
- name: 🧪 Test
4245
run: pnpm run test
4346

47+
- name: 📊 Report Coverage
48+
if: always()
49+
uses: davelosert/vitest-coverage-report-action@3c50566c523e04813df28de8f7c48dd97d663f1c # v2
50+
with:
51+
pr-number: auto
52+
4453
security:
4554
runs-on: ubuntu-latest
4655
steps:

demo/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { python } from "@codemirror/lang-python";
22
import { Prec, type Range } from "@codemirror/state";
33
import { Decoration, type DecorationSet, keymap, tooltips, ViewPlugin } from "@codemirror/view";
44
import { basicSetup, EditorView } from "codemirror";
5+
import { triggerOptions } from "../src/index.js";
56
import { aiExtension } from "../src/inline-edit/inline-edit.js";
67
import { PredictionBackend } from "../src/next-edit-prediction/backend.js";
78
import {
@@ -16,7 +17,6 @@ import { nextEditPrediction } from "../src/next-edit-prediction/extension.js";
1617
import { CURSOR_MARKER } from "../src/next-edit-prediction/types.js";
1718
import { insertDiffText } from "../src/next-edit-prediction/utils.js";
1819
import { promptHistory, storePrompt } from "../src/prompt-history/extension.js";
19-
import { triggerOptions } from "../src/index.js";
2020

2121
const logger = console;
2222

src/inline-edit/__tests__/inline-completion.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ describe("inline-completion", () => {
4747

4848
// Verify that fetchFn was called with the current state
4949
expect(mockFetchFn).toHaveBeenCalledTimes(1);
50-
expect(mockFetchFn).toHaveBeenCalledWith(expect.any(EditorState), expect.any(AbortSignal), expect.any(EditorView));
50+
expect(mockFetchFn).toHaveBeenCalledWith(
51+
expect.any(EditorState),
52+
expect.any(AbortSignal),
53+
expect.any(EditorView),
54+
);
5155
});
5256

5357
it("should accept inline completion", async () => {

src/inline-edit/trigger.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ export const triggerViewPlugin = ViewPlugin.fromClass(
126126
// Hide tooltip if hideOnBlur is enabled and editor doesn't have focus
127127
if (options.hideOnBlur && !view.hasFocus) {
128128
this.dom.style.display = "none";
129-
this.dom.setAttribute('aria-hidden', "true");
129+
this.dom.setAttribute("aria-hidden", "true");
130130
return;
131131
}
132132
view.requestMeasure({
@@ -157,25 +157,24 @@ export const triggerViewPlugin = ViewPlugin.fromClass(
157157
c.left <= scrollRect.right;
158158

159159
const isEndInParent = (c: { top: number; left: number }) =>
160-
!domRect || (
161-
c.top >= domRect.top &&
160+
!domRect ||
161+
(c.top >= domRect.top &&
162162
c.top <= domRect.bottom &&
163163
c.left >= domRect.left &&
164-
c.left <= domRect.right
165-
);
164+
c.left <= domRect.right);
166165

167166
const isInEditorViewport = isEndInEditor(fromCoords) || isEndInEditor(toCoords);
168167
const isInParentViewport = isEndInParent(fromCoords) || isEndInParent(toCoords);
169168

170169
// Hide tooltip if selection is not visible in either viewport
171170
if (!isInEditorViewport || !isInParentViewport) {
172171
this.dom.style.display = "none";
173-
this.dom.setAttribute('aria-hidden', "true");
172+
this.dom.setAttribute("aria-hidden", "true");
174173
return;
175174
}
176175

177176
this.dom.style.display = "flex";
178-
this.dom.setAttribute('aria-hidden', "false");
177+
this.dom.setAttribute("aria-hidden", "false");
179178

180179
// These measurements are definitely slow and we don't want to
181180
// do them very often! We may want to cache these in the future.
@@ -206,12 +205,12 @@ export const triggerViewPlugin = ViewPlugin.fromClass(
206205
this.dom.style.top = `${top}px`;
207206
requestAnimationFrame(() => {
208207
if (this.dom) {
209-
this.dom.setAttribute('aria-hidden', "false");
208+
this.dom.setAttribute("aria-hidden", "false");
210209
}
211210
});
212211
} else {
213212
this.dom.style.display = "none";
214-
this.dom.setAttribute('aria-hidden', "true");
213+
this.dom.setAttribute("aria-hidden", "true");
215214
}
216215
};
217216

vite.config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ export default defineConfig({
44
root: process.env.VITEST ? "." : "demo",
55
test: {
66
environment: "jsdom",
7+
coverage: {
8+
enabled: true,
9+
include: ["src/**"],
10+
exclude: ["demo/**", "scripts/**"],
11+
reportOnFailure: true,
12+
reporter: ["text", "html", "json-summary", "json"],
13+
},
714
watch: false,
815
},
916
base: "/codemirror-ai/",

0 commit comments

Comments
 (0)