Skip to content

Commit b06ae66

Browse files
OpenAPI http(s) import + in-editor report webview; fix make ci/CI divergence (#27)
<!-- agent-pmo:74cf183 --> ## TLDR Adds plain-`http://` support to the VS Code OpenAPI importer, renders saved playlist reports in an in-editor webview (no more blocking external-app modal), makes the redirect e2e test hermetic, upgrades the extension dev toolchain, adds website analytics + a Deslop gate, and fixes two `make ci`/CI-divergence bugs. ## Details **OpenAPI download over HTTP(S)** — `src/Napper.VsCode/src/openApiDownloader.ts` - `downloadSpec` selects the `http` client when the URL begins with `http://`, else `https`, so self-hosted/internal specs served over plain HTTP can be imported. Redirect-following and error handling are preserved; the response handler is shared between both clients. - New named constant `HTTP_SCHEME_PREFIX = 'http://'` in `constants.ts`. **Playlist report now opens inside VS Code** — `src/Napper.VsCode/src/extension.ts` - `savePlaylistReport` previously called `vscode.env.openExternal(Uri.file(report.html))`. On any host without an OS file→app association (headless CI, the extension-test window) that raises a blocking **"An error occurred opening an external program — No application found to open URL"** modal that must be dismissed by hand and stalls the automated run. - The report HTML is fully self-contained (inline styles), so it now renders in an in-process webview panel (`REPORT_PANEL_VIEW_TYPE`) titled `<playlist>-report`. The file is still written to disk and the "Report saved" message still shows. Hermetic, better UX, no external app needed. **Dev-dependency upgrades** — `package.json` + regenerated `package-lock.json` - `@types/node` 25.3→25.9, `@types/vscode` 1.95→1.120, `@vscode/vsce` 3.7→3.9, `eslint` 10.0→10.4, `mocha` 11.7.5→11.7.6, `prettier` 3.8.1→3.8.3, `ts-loader` 9.5→9.6, `typescript-eslint` 8.56→8.60, `webpack` 5.105→5.107, `webpack-cli` 6→7 (major). Marketplace `preview` flag flipped `true`→`false`. **Website Google Analytics** — `website/eleventy.config.js` - New Eleventy transform injects the gtag.js snippet (id `G-JNZW4P4DYD`) before `</head>` on every `.html` page. **CI-infrastructure fixes** — `Makefile` - `_test_vsix` now runs `npm run compile:e2e` (alongside `compile` + `compile:tests`). Previously `make` only compiled the unit suite, so the e2e suite ran from a **stale** build — masking source changes (it ran the old httpbin-based redirect test, which fails when httpbin is down). CI was unaffected because it runs `npm run pretest` (which includes `compile:e2e`); this realigns `make ci` with CI. - `_coverage_check` parses the Rust cobertura `line-rate` with `xmllint --xpath` instead of a greedy `sed` regex. The report is a single line, so the old regex matched the **last** `line-rate` (the empty `src/tests` package = `0`) and reported 0%, aborting the build despite genuine 100% line coverage. Uses a real XML parser per the repo's "no regex on structured data" rule. **Repo standards / tooling** - `.deslop.toml` (new): duplication gate `max_duplication_percent = 15.2` over the Rust Zed extension (Deslop does not yet analyse F#); ratchet-down only. Implements REPO-STANDARDS-SPEC `[CI-DESLOP]`. - `.gitignore`: stop ignoring `.idea/` and `.vscode/` so shared IDE config is committed per `[GITIGNORE-RULES]`. - `.claude/settings.json` (new): `autoMemoryEnabled: false`. ## How Do The Automated Tests Prove It Works? - **Redirect (hermetic)** — `openApiImport.e2e.test.ts › downloadSpec follows redirects` spins up a local `http.createServer` that 302-redirects `/redirect` → `/spec.json`, then asserts `downloadSpec` follows the redirect over plain HTTP and the parsed body has an `openapi` field. Exercises the new `http://` path with zero external dependency. Verified: `vscode-test --grep "follows redirects"` → passing. - **Report opens in-editor** — `playlist.e2e.test.ts › save report command creates HTML report file after playlist completes` now additionally asserts (through the UI) that a webview tab labelled `smoke-report` appears after the Save Report command — proving the report renders in VS Code with no blocking external-app modal. The csx save-report tests also pass. Verified: `vscode-test --grep "save report|follows redirects"` → 4 passing, no modal. - **Full `make ci`** (lint → test → build) passes locally end-to-end: Fantomas/Prettier/cargo-fmt, `dotnet build -warnaserror`, ESLint, clippy; F# tests (Napper.Core 97.9%, DotHttp 90.5%, Napper.Lsp 100%), Rust tarpaulin (100%, now parsed correctly), TS unit + extension-host e2e suites, all coverage thresholds, the universal VSIX package, and the NativeAOT CLI publish + `napper --version` contract check. ## Breaking Changes None. The HTTP(S) download change is additive (HTTPS stays default); the report now opens in-editor instead of an external browser (no behavioral loss — the file is still saved); dependency bumps are dev-only; Makefile fixes only touch build orchestration. All verified green by `make ci`. ## Follow-up: de-flake the e2e suite (drop httpbin.org) The first CI run on this PR went red on a pre-existing, unrelated flaky test — `runfile.e2e › running via URI opens same response panel as via document` — which ran a fixture against **httpbin.org** and timed out (30s) when httpbin was slow. httpbin.org is chronically unreliable (the redirect test was already migrated off it). To make CI reliably green: - Renamed fixture `get-httpbin.nap` → `get-shorthand.nap` and pointed it at a reliable real API (`jsonplaceholder.typicode.com/todos/1`). Updated all six e2e files that referenced it; the copy-curl URL assertion and the run-file test name were updated to match. - `openApiImport.e2e` `NONEXISTENT_URL` now uses a reliable jsonplaceholder 404 path instead of `httpbin.org/status/404`. - The only remaining httpbin strings are in two explorer tests that never make a network call (they assert file/tree state) plus one explanatory comment. ## Follow-up 2: correct the Rust coverage threshold (CI run 2 & 3) With the parser fixed, CI surfaced two more environment gaps: - **`xmllint` is not installed on the GitHub ubuntu runner** (exit 127). Switched the cobertura `line-rate` parse to `python3` + stdlib ElementTree — a real XML parser pre-installed on both GitHub runners and macOS. - **Phantom Rust threshold.** tarpaulin's line attribution is platform-divergent: macOS reports 67/67 = 100%, Linux CI reports 66/68 = 97.1% for identical code (the two "uncovered" lines — `match name {` and a struct-literal field — are already exercised by existing tests). The 99% threshold had been auto-ratcheted from the inflated macOS number, so CI could never meet it. Fixed by pinning the Rust threshold to 96 (`floor(CI%)−1`, matching every other project) and making the Rust coverage check **check-only** — auto-ratcheting platform-divergent coverage captures the wrong (highest) measurement. F#/TS ratchets are unchanged. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent 228035a commit b06ae66

27 files changed

Lines changed: 723 additions & 941 deletions

.claude/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"autoMemoryEnabled": false
3+
}

.deslop.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# agent-pmo:b636503
2+
# Deslop duplication gate — REPO-STANDARDS-SPEC [CI-DESLOP]
3+
# Single source of truth for this repo's duplication budget. Committed, PR-reviewed,
4+
# ratcheted DOWN only (never up without written justification).
5+
# CI runs `deslop .`, which reads this file and exits 3 (tanking the build) when
6+
# measured repo-wide duplication exceeds the value below.
7+
# Docs: https://deslop.live/docs/for-ai/
8+
#
9+
# SCOPE NOTE: Napper's primary language is F#, which Deslop does not yet analyse.
10+
# Deslop here measures the supported component only — the Rust Zed extension
11+
# (src/Napper.Zed, ~1033 LOC). max_duplication_percent below is the CURRENTLY
12+
# MEASURED 15.0% rounded up by a small float-jitter buffer. Ratchet it DOWN as the
13+
# Rust duplication is reduced; never raise it without written PR justification.
14+
[threshold]
15+
max_duplication_percent = 15.2

.github/workflows/ci.yml

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ jobs:
1515
runs-on: ubuntu-latest
1616
timeout-minutes: 10
1717
steps:
18-
- uses: actions/checkout@v4
18+
- uses: actions/checkout@v6
1919

20-
- uses: actions/setup-node@v4
20+
- uses: actions/setup-node@v6
2121
with:
2222
node-version: 22
2323
cache: npm
2424
cache-dependency-path: src/Napper.VsCode/package-lock.json
2525

26-
- uses: actions/setup-dotnet@v4
26+
- uses: actions/setup-dotnet@v5
2727
with:
2828
dotnet-version: "10.0.x"
2929

@@ -32,14 +32,14 @@ jobs:
3232
components: clippy, rustfmt
3333

3434
- name: Cache NuGet packages
35-
uses: actions/cache@v4
35+
uses: actions/cache@v5
3636
with:
3737
path: ~/.nuget/packages
3838
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.fsproj') }}
3939
restore-keys: ${{ runner.os }}-nuget-
4040

4141
- name: Cache Cargo registry and build
42-
uses: actions/cache@v4
42+
uses: actions/cache@v5
4343
with:
4444
path: |
4545
~/.cargo/registry
@@ -96,15 +96,15 @@ jobs:
9696
timeout-minutes: 10
9797
needs: lint
9898
steps:
99-
- uses: actions/checkout@v4
99+
- uses: actions/checkout@v6
100100

101-
- uses: actions/setup-node@v4
101+
- uses: actions/setup-node@v6
102102
with:
103103
node-version: 22
104104
cache: npm
105105
cache-dependency-path: src/Napper.VsCode/package-lock.json
106106

107-
- uses: actions/setup-dotnet@v4
107+
- uses: actions/setup-dotnet@v5
108108
with:
109109
dotnet-version: "10.0.x"
110110

@@ -113,14 +113,14 @@ jobs:
113113
components: clippy, rustfmt
114114

115115
- name: Cache NuGet packages
116-
uses: actions/cache@v4
116+
uses: actions/cache@v5
117117
with:
118118
path: ~/.nuget/packages
119119
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.fsproj') }}
120120
restore-keys: ${{ runner.os }}-nuget-
121121

122122
- name: Cache Cargo registry and build
123-
uses: actions/cache@v4
123+
uses: actions/cache@v5
124124
with:
125125
path: |
126126
~/.cargo/registry
@@ -194,39 +194,39 @@ jobs:
194194

195195
- name: Upload TypeScript coverage
196196
if: always()
197-
uses: actions/upload-artifact@v4
197+
uses: actions/upload-artifact@v7
198198
with:
199199
name: typescript-coverage
200200
path: src/Napper.VsCode/coverage/
201201
retention-days: 7
202202

203203
- name: Upload F# coverage
204204
if: always()
205-
uses: actions/upload-artifact@v4
205+
uses: actions/upload-artifact@v7
206206
with:
207207
name: fsharp-coverage
208208
path: coverage/fsharp/report/
209209
retention-days: 7
210210

211211
- name: Upload DotHttp coverage
212212
if: always()
213-
uses: actions/upload-artifact@v4
213+
uses: actions/upload-artifact@v7
214214
with:
215215
name: dothttp-coverage
216216
path: coverage/dothttp/report/
217217
retention-days: 7
218218

219219
- name: Upload Napper.Lsp coverage
220220
if: always()
221-
uses: actions/upload-artifact@v4
221+
uses: actions/upload-artifact@v7
222222
with:
223223
name: lsp-coverage
224224
path: coverage/lsp/report/
225225
retention-days: 7
226226

227227
- name: Upload Rust coverage
228228
if: always()
229-
uses: actions/upload-artifact@v4
229+
uses: actions/upload-artifact@v7
230230
with:
231231
name: rust-coverage
232232
path: coverage/rust/report/
@@ -238,20 +238,20 @@ jobs:
238238
timeout-minutes: 10
239239
needs: test
240240
steps:
241-
- uses: actions/checkout@v4
241+
- uses: actions/checkout@v6
242242

243-
- uses: actions/setup-node@v4
243+
- uses: actions/setup-node@v6
244244
with:
245245
node-version: 22
246246
cache: npm
247247
cache-dependency-path: src/Napper.VsCode/package-lock.json
248248

249-
- uses: actions/setup-dotnet@v4
249+
- uses: actions/setup-dotnet@v5
250250
with:
251251
dotnet-version: "10.0.x"
252252

253253
- name: Cache NuGet packages
254-
uses: actions/cache@v4
254+
uses: actions/cache@v5
255255
with:
256256
path: ~/.nuget/packages
257257
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.fsproj') }}
@@ -270,7 +270,7 @@ jobs:
270270
run: npx @vscode/vsce package --no-dependencies --skip-license
271271

272272
- name: Upload VSIX
273-
uses: actions/upload-artifact@v4
273+
uses: actions/upload-artifact@v7
274274
with:
275275
name: vsix
276276
path: src/Napper.VsCode/*.vsix
@@ -282,13 +282,13 @@ jobs:
282282
timeout-minutes: 20
283283
needs: lint
284284
steps:
285-
- uses: actions/checkout@v4
285+
- uses: actions/checkout@v6
286286

287-
- uses: actions/setup-dotnet@v4
287+
- uses: actions/setup-dotnet@v5
288288
with:
289289
dotnet-version: "10.0.x"
290290

291-
- uses: actions/setup-node@v4
291+
- uses: actions/setup-node@v6
292292
with:
293293
node-version: 22
294294

@@ -325,9 +325,9 @@ jobs:
325325
runs-on: ubuntu-latest
326326
timeout-minutes: 10
327327
steps:
328-
- uses: actions/checkout@v4
328+
- uses: actions/checkout@v6
329329

330-
- uses: actions/setup-node@v4
330+
- uses: actions/setup-node@v6
331331
with:
332332
node-version: 22
333333
cache: npm
@@ -347,9 +347,9 @@ jobs:
347347
timeout-minutes: 10
348348
needs: lint
349349
steps:
350-
- uses: actions/checkout@v4
350+
- uses: actions/checkout@v6
351351

352-
- uses: actions/setup-node@v4
352+
- uses: actions/setup-node@v6
353353
with:
354354
node-version: 22
355355
cache: npm

.github/workflows/deploy-pages.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ jobs:
1818
runs-on: ubuntu-latest
1919
timeout-minutes: 10
2020
steps:
21-
- uses: actions/checkout@v4
21+
- uses: actions/checkout@v6
2222

23-
- uses: actions/setup-node@v4
23+
- uses: actions/setup-node@v6
2424
with:
2525
node-version: 22
2626
cache: npm
@@ -34,9 +34,9 @@ jobs:
3434
working-directory: website
3535
run: npx eleventy
3636

37-
- uses: actions/configure-pages@v5
37+
- uses: actions/configure-pages@v6
3838

39-
- uses: actions/upload-pages-artifact@v3
39+
- uses: actions/upload-pages-artifact@v5
4040
with:
4141
path: website/_site/
4242

@@ -49,5 +49,5 @@ jobs:
4949
name: github-pages
5050
url: ${{ steps.deployment.outputs.page_url }}
5151
steps:
52-
- uses: actions/deploy-pages@v4
52+
- uses: actions/deploy-pages@v5
5353
id: deployment

0 commit comments

Comments
 (0)