Skip to content

Commit 20145d3

Browse files
authored
Merge pull request #16 from greylag-ci/ux-polish
release: v0.2.0 — Findings panel + status bar + CodeLens + navigation + per-provider toggles
2 parents ffbf0f0 + 4a7f305 commit 20145d3

28 files changed

Lines changed: 4456 additions & 235 deletions

.github/workflows/ci.yml

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,17 @@ permissions:
1717

1818
jobs:
1919
check:
20-
runs-on: ubuntu-latest
20+
# The extension is cross-platform; the LSP child-process spawn
21+
# path, the bundle loader, and several file-path helpers are all
22+
# Windows-sensitive. Running the gate on three OSes catches the
23+
# LF/CRLF and path-separator bugs that single-OS CI silently
24+
# ignores. The matrix shares the same step list — only the vsix
25+
# upload and the network-bound npm audit are pinned to Linux.
26+
strategy:
27+
fail-fast: false
28+
matrix:
29+
os: [ubuntu-latest, windows-latest, macos-latest]
30+
runs-on: ${{ matrix.os }}
2131
steps:
2232
- uses: actions/checkout@v6
2333

@@ -31,6 +41,15 @@ jobs:
3141
- name: Lint
3242
run: npm run lint
3343

44+
- name: Marketplace description length
45+
# The marketplace truncates listing descriptions around 145
46+
# characters in search results. Anything longer loses signal
47+
# before users click through. The current copy hugs the limit
48+
# deliberately — this step keeps future edits honest.
49+
if: matrix.os == 'ubuntu-latest'
50+
run: |
51+
node -e 'const d=require("./package.json").description; if(d.length>145){console.error("description is "+d.length+" chars (max 145):",d);process.exit(1)}'
52+
3453
- name: TypeScript compile
3554
run: npm run compile
3655

@@ -44,17 +63,31 @@ jobs:
4463
# asserts activate/deactivate are exported.
4564
run: npm run smoke
4665

66+
- name: Integration tests (real VS Code)
67+
# @vscode/test-electron boots a real extension host and runs
68+
# the mocha suite under src/test/integration/. Verifies the
69+
# activation / command / view contracts that unit tests can
70+
# only approximate. Linux-only — VS Code needs an X server
71+
# (xvfb-run) on headless runners; Windows/macOS in this
72+
# matrix already exercise the platform-specific paths via the
73+
# unit suite + bundle smoke.
74+
if: matrix.os == 'ubuntu-latest'
75+
run: xvfb-run -a npm run test:integration
76+
4777
- name: npm audit (prod deps, high+)
78+
# Network-bound and platform-independent; one run is enough.
79+
if: matrix.os == 'ubuntu-latest'
4880
run: npm audit --omit=dev --audit-level=high
4981

5082
- name: Verify vsix packs cleanly
5183
# vsce is a pinned devDependency (see package.json) — Dependabot
5284
# bumps it via the npm config. `npm ci` has already installed it.
53-
run: |
54-
npx vsce package --out pipeline-check.vsix
55-
ls -lh pipeline-check.vsix
85+
run: npx vsce package --out pipeline-check.vsix
5686

5787
- uses: actions/upload-artifact@v7
88+
# Single artefact upload from the Linux job; identical-name
89+
# uploads from the matrix would collide.
90+
if: matrix.os == 'ubuntu-latest'
5891
with:
5992
name: vsix
6093
path: pipeline-check.vsix

.github/workflows/publish.yml

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ name: Publish
66
# VS Code Marketplace and Open VSX, then attaches the .vsix to a
77
# GitHub release.
88
#
9+
# Tag-naming convention:
10+
# - `v0.1.0` (stable) → stable marketplace channel.
11+
# - `v0.1.0-rc.1` (pre-release) → pre-release marketplace channel,
12+
# GitHub release marked `prerelease`.
13+
# Detection is by the presence of a `-` after the semver core; see
14+
# the "Detect pre-release tag" step below.
15+
#
916
# Required repo secrets:
1017
# - VSCE_PAT — Azure DevOps Personal Access Token, scope
1118
# `Marketplace > Acquire and Manage`. Bound to the
@@ -109,37 +116,60 @@ jobs:
109116
- name: Bundle smoke
110117
run: npm run smoke
111118

119+
- name: Detect pre-release tag
120+
# A tag like `v0.2.0-rc.1` (anything with a `-` after the
121+
# semver core) ships to the marketplace's pre-release channel
122+
# and the GitHub release is marked prerelease. Stable tags
123+
# (`v0.2.0`) ship to the stable channel. Detection is purely
124+
# by the version string — keeps the convention discoverable
125+
# via `git tag`.
126+
run: |
127+
set -euo pipefail
128+
version=$(node -p "require('./package.json').version")
129+
if [[ "$version" == *-* ]]; then
130+
echo "Pre-release tag detected: $version"
131+
echo "PRERELEASE_FLAG=--pre-release" >> "$GITHUB_ENV"
132+
echo "GH_PRERELEASE=--prerelease" >> "$GITHUB_ENV"
133+
else
134+
echo "Stable tag: $version"
135+
echo "PRERELEASE_FLAG=" >> "$GITHUB_ENV"
136+
echo "GH_PRERELEASE=" >> "$GITHUB_ENV"
137+
fi
138+
112139
- name: Package vsix
113140
# vsce and ovsx are pinned devDependencies in package.json, so
114141
# `npm ci` above installed the exact versions and Dependabot
115142
# bumps them via the standard npm config. `npx` here resolves
116143
# the local binary — no fresh fetch with PATs in env.
117144
run: |
118145
version=$(node -p "require('./package.json').version")
119-
npx vsce package --out "pipeline-check-${version}.vsix"
146+
npx vsce package $PRERELEASE_FLAG --out "pipeline-check-${version}.vsix"
120147
ls -lh "pipeline-check-${version}.vsix"
121148
echo "VSIX_PATH=pipeline-check-${version}.vsix" >> $GITHUB_ENV
122149
123150
- name: Publish to VS Code Marketplace
124151
env:
125152
VSCE_PAT: ${{ secrets.VSCE_PAT }}
126153
run: |
127-
npx vsce publish \
154+
npx vsce publish $PRERELEASE_FLAG \
128155
--packagePath "$VSIX_PATH" \
129156
--pat "$VSCE_PAT"
130157
131158
- name: Publish to Open VSX
132159
env:
133160
OVSX_PAT: ${{ secrets.OVSX_PAT }}
134161
run: |
135-
npx ovsx publish "$VSIX_PATH" \
162+
# Open VSX (ovsx >= 0.10) honours --pre-release the same
163+
# way vsce does. Older versions ignore the flag silently,
164+
# so this stays safe across minor bumps.
165+
npx ovsx publish $PRERELEASE_FLAG "$VSIX_PATH" \
136166
--pat "$OVSX_PAT"
137167
138168
- name: Create GitHub release
139169
env:
140170
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
141171
run: |
142172
version=$(node -p "require('./package.json').version")
143-
gh release create "v${version}" "$VSIX_PATH" \
173+
gh release create "v${version}" "$VSIX_PATH" $GH_PRERELEASE \
144174
--title "v${version}" \
145175
--notes-file <(awk '/^## \[/{n++} n==2{exit} n==1{print}' CHANGELOG.md)

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ web_modules/
7777
# Next.js build output
7878
.next
7979
out
80+
out-test
8081

8182
# Nuxt.js build / generate output
8283
.nuxt

.vscode-test.mjs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Configuration for `@vscode/test-cli`, which boots a real VS Code
2+
// extension host so we can verify the contracts that unit tests can
3+
// only approximate: that activation actually fires, commands really
4+
// register, the view appears in the activity bar. The compiled tests
5+
// live in `out-test/` (separate from the esbuild bundle in `dist/`)
6+
// and use mocha-bdd-ui — same convention every official VS Code
7+
// extension uses.
8+
9+
import { defineConfig } from "@vscode/test-cli";
10+
11+
export default defineConfig({
12+
// Compiled test files; `tsconfig.integration.json` emits them.
13+
files: "out-test/test/integration/**/*.test.js",
14+
// Open the deliberately-vulnerable sample workflow as the workspace
15+
// root so activation events fire (workspaceContains:**/.github/workflows/*).
16+
workspaceFolder: "test-fixtures/sample-workflow",
17+
// Tests need the extension's commands and views registered before
18+
// they run; without a sane timeout, mocha may fail before the
19+
// extension finishes activating in slow CI environments.
20+
mocha: {
21+
// TDD ui exports `suite` / `test` (matching what every official
22+
// VS Code extension uses). BDD's `describe` / `it` would need a
23+
// re-write of the test files; staying with TDD keeps the
24+
// convention familiar.
25+
ui: "tdd",
26+
timeout: 20000,
27+
color: true,
28+
},
29+
});

.vscodeignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@ test-fixtures/**
66
scripts/**
77
docs/**
88
out/**
9+
out-test/**
910
ROADMAP.md
1011
.gitignore
1112
.eslintrc.json
13+
.vscode-test.mjs
1214
tsconfig.json
15+
tsconfig.integration.json
16+
vitest.config.ts
1317
**/*.map
1418
**/*.ts
1519
**/tsconfig.json

CHANGELOG.md

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,163 @@ All notable changes to the Pipeline-Check VS Code extension. The
44
format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
55
versions follow [SemVer](https://semver.org/).
66

7+
> **Release note for publish.yml:** the release-notes extractor (an
8+
> `awk` script in publish.yml) prints every line between the **first**
9+
> and **second** `## [` headers. When cutting a release, fold the
10+
> entries under `## [Unreleased]` into the new `## [X.Y.Z] — <date>`
11+
> section **above** Unreleased, or remove the Unreleased block for the
12+
> release commit. Otherwise the GitHub release ships boilerplate.
13+
14+
## [0.2.0] — 2026-05-19
15+
16+
Closes 24 of 29 items from the 2026-05-19 in-depth UX/code review.
17+
Adds the activity-bar Findings tree's missing affordances (status bar,
18+
CodeLens, navigation, context menus, per-provider toggles), the
19+
release-tooling polish (`production` environment gate, pre-release
20+
channel, three-OS CI, integration tests), and the discovery /
21+
accessibility pass.
22+
23+
**Heads-up for users with non-standard workflow paths:** the
24+
extension's `activationEvents` now match only the
25+
`workspaceContains:` patterns shared with the LSP `documentSelector`
26+
(plus `onStartupFinished` so the activity-bar slot is always
27+
visible). If your repo keeps CI definitions outside the standard
28+
locations (e.g. `pipelines/build.yml` instead of
29+
`.github/workflows/*.yml`), the extension still activates on
30+
`onStartupFinished`, but the LSP only scans files matching the
31+
document selector. Use `pipelineCheck.serverArgs` to point the LSP
32+
at a different path or symlink your custom config into a standard
33+
location.
34+
35+
### Added
36+
37+
- **Inline CodeLens summary.** Each scanned file carries a
38+
`Pipeline-Check: 2 critical · 1 high` lens at line 1. Click reveals
39+
the Findings panel. Re-emits on every diagnostic publish so the
40+
text tracks the latest scan. (R26)
41+
- **Status bar item.** Bottom-left of the window, shows the top two
42+
non-zero severities (e.g. `$(shield) 3C 1H`) with a tooltip that
43+
breaks down the full per-severity tally. Click reveals the
44+
Findings panel. (R9)
45+
- **Keyboard navigation.** `Alt+F8` / `Shift+Alt+F8` jump between
46+
Pipeline-Check findings in editor order (fsPath ascending, then by
47+
line); wraps at both ends. Mirrors VS Code's `F8` muscle memory
48+
for the global "Next Problem" command. (R12)
49+
- **Per-provider toggles.** New `pipelineCheck.disabledProviders`
50+
setting silences whole providers. `dockerfile` covers both
51+
`Dockerfile` and `Containerfile` (same syntax). Useful in a
52+
monorepo where Pipeline-Check would otherwise lint a sub-project's
53+
Dockerfile that has its own lint pipeline. (R25)
54+
- **Rule documentation link in leaf tooltip.** When the server
55+
publishes a `Diagnostic.code.target` URL, the Findings tree's
56+
leaf tooltip appends a clickable
57+
`$(book) <rule-id> documentation` link below the message body. (R8)
58+
- **Client-side structured logging.** The extension's output channel
59+
now interleaves `[client] HH:MM:SS.mmm` lines around activation
60+
and command invocations with the LSP's `window/logMessage`
61+
traffic. Easier to triage bug reports — start/ok/failed
62+
breadcrumbs land in the same surface users already focus via
63+
*Show language server output*. (R16)
64+
- **Pre-release channel.** Tags like `v0.2.0-rc.1` ship to the
65+
marketplace pre-release channel; the matching GitHub release is
66+
marked `prerelease`. Detection is by the presence of a `-` after
67+
the semver core. (R24)
68+
- **Right-click context menu on Findings tree leaves.** *Open Rule
69+
Documentation* opens the URL the server published via
70+
`Diagnostic.code.target` in the system browser; *Copy Rule ID*
71+
writes the rule's identifier to the clipboard. Same data the leaf
72+
tooltip already surfaces, now available without keeping the
73+
tooltip open.
74+
- **`pipelineCheck.codeLens.enabled` setting.** Defaults to `true`.
75+
Hides the line-1 file-summary CodeLens for users who find it
76+
intrusive without disabling CodeLens globally. Toggle takes effect
77+
on the next render — no extension restart.
78+
- **`pipelineCheck.copyInstallCommand` command.** Copies
79+
`pip install "pipeline-check[lsp]"` to the clipboard. Surfaced
80+
from the Findings welcome state and from the Command Palette so
81+
users can re-find it after dismissing the first-run error toast.
82+
83+
### Changed
84+
85+
- **Welcome state of the Findings panel teaches.** Now leads with
86+
what Pipeline-Check does + a *Copy install command* link for the
87+
Python `[lsp]` extra, then onboarding ("open a workflow…"), then
88+
the Alt+F8 / Shift+Alt+F8 keyboard hint, then a `---` separator
89+
and the recovery actions (Restart, Open Log) demoted below.
90+
- **`onStartupFinished` activation event.** The extension now wakes
91+
up after VS Code's start-up barrier so the activity-bar slot is
92+
visible in every workspace — not just ones with a
93+
`workspaceContains:` match. The LSP child process still only
94+
spawns when the `documentSelector` matches an open document, so
95+
there's no idle-Python-process cost.
96+
- **Status bar item hides in non-CI workspaces.** On activation we
97+
do a one-shot `findFiles` for any of the trigger patterns; the
98+
status bar item only shows once we've seen evidence the workspace
99+
is CI-relevant (either a match or an actual diagnostic publish).
100+
Stops `$(shield) clean` cluttering the bottom-left in frontend
101+
projects that happen to have Pipeline-Check installed alongside
102+
other linters.
103+
- **Status bar accessibility label.** Screen readers now hear
104+
"Pipeline-Check: 3 critical, 1 high" instead of the codicon
105+
shortcode + letter-by-letter abbreviation.
106+
- **Status bar tooltip teaches Alt+F8.** The trailing line of the
107+
tooltip ("Alt+F8 / Shift+Alt+F8 to step through findings") is the
108+
primary discovery surface for the navigation keybindings.
109+
- **Command titles use title case** for VS Code's convention:
110+
"Restart Language Server", "Show Language Server Output",
111+
"Refresh Findings". Existing "Go to Next Finding" and "Change
112+
Grouping" stay the same. Command IDs are unchanged — settings,
113+
keybindings, and automation continue to work.
114+
115+
- **`@vscode/test-electron` integration suite** now runs in CI
116+
(Linux only, via `xvfb-run -a`). Five tests pin activation, the
117+
command-registration contract, the Findings view registration,
118+
the configuration schema completeness, and the workspace-trust
119+
capability declarations. Catches what unit tests can only
120+
approximate. (R17)
121+
- **Three-OS test matrix** — `[ubuntu-latest, windows-latest,
122+
macos-latest]`. The LSP child-process spawn path is
123+
Windows-sensitive; matrix CI catches the LF/CRLF and
124+
path-separator bugs single-OS CI silently misses. (R21)
125+
- **Activation surface narrowed.** Triggers are
126+
`workspaceContains:` patterns matching the providers we actually
127+
scan (the `documentSelector` uses the same patterns). Opening an
128+
unrelated `package.json` or `mkdocs.yml` no longer wakes up the
129+
extension. (H4)
130+
- **Trigger-pattern list lives in one place.** Extracted into
131+
`src/providers.ts` as a single `PROVIDERS` map; the `documentSelector`,
132+
`activationEvents`, and the LSP middleware's per-provider filter
133+
all read from it. A regression test asserts the manifest's
134+
`activationEvents` stay in lockstep with the patterns. (R14)
135+
- **Shared `vi.mock("vscode")` factory** under `src/__testStubs__/`.
136+
Unit tests now share a single stub instead of redefining the
137+
surface per file. (R18)
138+
- **Marketplace description length** gated in CI at the
139+
145-character truncation point so future edits don't blow it. (R20)
140+
141+
### Fixed
142+
143+
- **`Restart language server` toast no longer fires on failure**
144+
if the server failed to come up, the error notification already
145+
carries the install hint; the success toast used to fire too,
146+
giving the user contradictory signals. (R2)
147+
- **`stopClient` has a 2-second hard ceiling** on the LSP child's
148+
shutdown. A deadlocked server used to hold the deactivate path
149+
indefinitely; VS Code reported "Window not responding" until the
150+
user force-quit. (R3)
151+
- **`groupByFile` no longer round-trips Uri through string** for
152+
every group node. Bucket value carries the original Uri. (R4)
153+
- **`compareByLocation` sorts on `fsPath`** instead of the full URI
154+
string. Cross-scheme entries (file:// vs untitled://) no longer
155+
bunch at one end. (R5)
156+
- **`collectFindings` is memoised per refresh** — buildRoot and
157+
updateBadge used to walk the global diagnostic store twice per
158+
refresh. (R6)
159+
- **`onDidChangeDiagnostics` skips refreshes from unrelated
160+
publishers.** ESLint / mypy / redhat.yaml keystroke chatter no
161+
longer rebuilds the tree. The skip-check also catches *clears*
162+
(a stale leaf can't outlive a cleared file). (R7)
163+
7164
## [0.1.1] — 2026-05-19
8165

9166
Production-readiness pass. v0.1.0 was effectively unusable on a clean

0 commit comments

Comments
 (0)