Skip to content

Commit a463a62

Browse files
committed
ci(ui-merge): port objectui's lockfile-integrity gate into Type Check UI, retire lockfile-dedupe and the shadcn-check report
Rows 19, 18 and 26 of the objectui workflow roster. - Row 19: check:lockfile-integrity runs as a pull_request-only, continue-on-error step of Type Check UI, before the install, against origin/<base>; the integrity test pins the step, the deep checkout and the alarm-only shape against root ci.yml. - Row 18: the check:lockfile-dedupe alias, its script and its test are deleted (report-only, nothing else reads them). - Row 26: shadcn-check-report.mjs (the weekly workflow's classifier) and its test are deleted; shadcn:check / shadcn:analyze stay, they are the components package's documented maintainer commands. Claude-Session: https://claude.ai/code/session_01ADHkmSracEMN5RmM9xs4Fu Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7bb8084 commit a463a62

7 files changed

Lines changed: 82 additions & 2093 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3384,6 +3384,32 @@ jobs:
33843384
- name: Verify type-check coverage
33853385
run: pnpm --dir ui run type-check:coverage
33863386

3387+
# objectui's `lockfile-integrity.yml` (objectui#8326), row 19 of the
3388+
# objectstack#25697 workflow roster, ported by objectstack#26717: a pull
3389+
# request's `pnpm-lock.yaml` may not give any package a second physical
3390+
# copy. The script's header has the mechanism and its boundary.
3391+
#
3392+
# It lives here because this job already checks out with
3393+
# `fetch-depth: 0`, so `origin/<base>` and the merge base are in the
3394+
# clone, and because it runs on every change to `pnpm-lock.yaml` (the
3395+
# `ui` filter lists it). Before the install on purpose: the gate reads
3396+
# two text files with Node builtins only, which Lint UI's pre-install
3397+
# import graph check holds. `pull_request` only, because the gate's
3398+
# subject is the pull request's delta against its base; a push or queue
3399+
# run has none of its own.
3400+
#
3401+
# ⛔ `continue-on-error` keeps it an ALARM, as objectui ran it: a finding
3402+
# prints an `::error::` annotation naming the packages on the pull
3403+
# request and does NOT fail this required job. Making it blocking is a
3404+
# maintainer decision (`NOT_A_GATE` in `ui/scripts/dependabot-merge-gate.mjs`
3405+
# says why), not a step edit.
3406+
- name: check:lockfile-integrity — compare this pull request's lockfile with its merge base
3407+
if: github.event_name == 'pull_request'
3408+
continue-on-error: true
3409+
env:
3410+
BASE_REF: ${{ github.base_ref }}
3411+
run: pnpm --dir ui run check:lockfile-integrity --base-ref "origin/${BASE_REF}"
3412+
33873413
- name: Install dependencies
33883414
run: pnpm install --frozen-lockfile
33893415

‎ui/package.json‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@
8484
"check:merge-queue-head": "node scripts/check-merge-queue-head.mjs --self-test",
8585
"check:required-check-set": "node scripts/check-required-check-set.mjs --self-test",
8686
"check:lockfile-integrity": "node scripts/check-lockfile-integrity.mjs",
87-
"check:lockfile-dedupe": "node scripts/check-lockfile-dedupe.mjs",
8887
"merge-queue-head": "node scripts/check-merge-queue-head.mjs",
8988
"check:pre-install-import-graph": "node scripts/check-pre-install-import-graph.mjs",
9089
"check:test-path-roots": "node scripts/check-test-path-roots.mjs",

‎ui/scripts/__tests__/check-lockfile-dedupe.test.ts‎

Lines changed: 0 additions & 600 deletions
This file was deleted.

‎ui/scripts/__tests__/check-lockfile-integrity.test.ts‎

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { fileURLToPath } from 'node:url';
2525
import { describe, expect, it } from 'vitest';
2626
import { lockfilePath } from '../workspace-root.mjs';
2727

28+
import { jobBlock, rootCi, rootWorkflow, rootWorkflowFiles, uiRun, withoutComments } from './helpers/root-ci';
2829
import { NOT_A_GATE, OPTIONAL_CONTEXTS, REQUIRED_CONTEXTS } from '../dependabot-merge-gate.mjs';
2930
import {
3031
compareLockfiles,
@@ -38,7 +39,7 @@ const GATE = path.join(repoRoot, 'scripts/check-lockfile-integrity.mjs');
3839
const LOCKFILE = lockfilePath();
3940
const realLock = fs.readFileSync(LOCKFILE, 'utf8');
4041

41-
/** The check-run name the workflow's job produces. */
42+
/** The check-run name objectui's own job produced, the name the Dependabot merge gate classifies. */
4243
const CHECK_NAME = 'Lockfile Integrity Check';
4344

4445
describe('the gate runs its own self-test', () => {
@@ -191,15 +192,61 @@ describe('cause 2 — a declared dependency forks with no version moving (object
191192
});
192193
});
193194

194-
describe('the gate is classified the way the dispatch reserved', () => {
195-
// `exists and runs the gate` and `checks out deep enough to have a merge
196-
// base` retired with objectstack#25712. They read objectui's
197-
// `lockfile-integrity.yml`, which runs nowhere under the monorepo: GitHub
198-
// runs the root `.github/workflows/` alone. That workflow is row 19 of the
199-
// objectstack#25697 workflow roster, "kept, follow-up port", re-aimed at the
200-
// one root `pnpm-lock.yaml`; the port brings both pins back against the root
201-
// job that runs the gate.
195+
describe('the gate is wired into the root CI (objectstack#26717)', () => {
196+
// objectui ran it in its own `lockfile-integrity.yml`, which runs nowhere
197+
// under the monorepo: GitHub runs the root `.github/workflows/` alone. Row 19
198+
// of the objectstack#25697 workflow roster ported it as one step of root
199+
// `ci.yml`'s `type-check-ui` job, re-aimed at the one root `pnpm-lock.yaml`.
200+
// The two pins objectui kept on its workflow (`exists and runs the gate`,
201+
// `checks out deep enough to have a merge base`) read that job now.
202+
const JOB = 'type-check-ui';
203+
const STEP_NAME = 'check:lockfile-integrity — ';
204+
const COMMAND = `${uiRun('check:lockfile-integrity')} --base-ref "origin/\${BASE_REF}"`;
205+
206+
/** The step's own lines, from its `- name:` to the next step. Throws when it is gone. */
207+
function step(): string {
208+
const block = withoutComments(jobBlock(rootCi(), JOB));
209+
const start = block.indexOf(`- name: ${STEP_NAME}`);
210+
if (start === -1) throw new Error(`ci.yml job ${JOB} has no step named ${STEP_NAME}…`);
211+
const next = block.indexOf('\n - ', start + 1);
212+
return next === -1 ? block.slice(start) : block.slice(start, next);
213+
}
214+
215+
it('exists and runs the gate against the pull request base', () => {
216+
expect(step()).toContain(`run: ${COMMAND}`);
217+
expect(step()).toContain('BASE_REF: ${{ github.base_ref }}');
218+
expect(step()).toContain("if: github.event_name == 'pull_request'");
219+
});
220+
221+
it('checks out deep enough to have a merge base', () => {
222+
// A shallow clone has no merge base, and the script exits 2 rather than
223+
// guess one: a reading that never measured the change.
224+
const block = withoutComments(jobBlock(rootCi(), JOB));
225+
const checkout = block.indexOf('uses: actions/checkout@');
226+
expect(checkout).toBeGreaterThan(-1);
227+
expect(block.indexOf('fetch-depth: 0', checkout)).toBeGreaterThan(checkout);
228+
expect(block.indexOf('fetch-depth: 0', checkout)).toBeLessThan(block.indexOf(`- name: ${STEP_NAME}`));
229+
});
202230

231+
it('⛔ stays an alarm in a required job: continue-on-error, before the install', () => {
232+
// The step's finding must not fail Type Check UI; enrolling the gate is
233+
// the maintainer's decision (the classification below). Before the
234+
// install, because the script needs nothing installed.
235+
expect(step()).toContain('continue-on-error: true');
236+
const block = withoutComments(jobBlock(rootCi(), JOB));
237+
expect(block.indexOf(`- name: ${STEP_NAME}`)).toBeLessThan(block.indexOf('run: pnpm install --frozen-lockfile'));
238+
});
239+
240+
it('runs in that one place: no other root workflow carries it', () => {
241+
const carriers = rootWorkflowFiles().filter((file) =>
242+
withoutComments(rootWorkflow(file)).includes('check:lockfile-integrity'),
243+
);
244+
expect(carriers).toEqual(['ci.yml']);
245+
expect(withoutComments(rootCi()).split('check:lockfile-integrity').length - 1).toBe(2); // the name and the run
246+
});
247+
});
248+
249+
describe('the gate is classified the way the dispatch reserved', () => {
203250
it('⛔ is classified as NOT a blocking context (the maintainer floor)', () => {
204251
expect(Object.keys(NOT_A_GATE)).toContain(CHECK_NAME);
205252
expect(REQUIRED_CONTEXTS).not.toContain(CHECK_NAME);

0 commit comments

Comments
 (0)