Skip to content

fix: restore CI on develop (lockfile drift + workflow regressions)#407

Open
colinswinney wants to merge 9 commits intodevelopfrom
fix/lockfile-drift
Open

fix: restore CI on develop (lockfile drift + workflow regressions)#407
colinswinney wants to merge 9 commits intodevelopfrom
fix/lockfile-drift

Conversation

@colinswinney
Copy link
Copy Markdown

@colinswinney colinswinney commented May 6, 2026

Summary

Every CI run on develop since #405 (2026-04-01) has been red. Jest and ESLint died at npm ci, and four other workflows (Cypress, compressed-size, release_testing, plus two cypress.config.js blockers) had latent regressions that the broken install pipeline was masking. This PR fixes them all.

Lockfile fix

The security-patch merges in #405 left package-lock.json partially regenerated — some resolved versions (notably @wordpress/eslint-plugin@18.1.0) no longer satisfied the version ranges declared by their parents, and a tree of transitive entries went missing. Every CI npm ci failed with:

npm error code EUSAGE
npm error Invalid: lock file's @wordpress/eslint-plugin@18.1.0 does not satisfy @wordpress/eslint-plugin@17.13.0
npm error Missing: @wordpress/eslint-plugin@18.1.0 from lock file
npm error Missing: cosmiconfig@7.1.0 from lock file
... (dozens more)

Re-resolved with npm install --package-lock-only on Node 22.22.2 / npm 10.9.7 (matching the bundled-npm version CI runners use). package.json is unchanged. The diff is purely additive — it adds the missing transitive entries without bumping any direct dependency.

Workflow & config fixes

Once npm ci succeeded, the remaining failures surfaced and are addressed here:

Cypress workspace build (e2e-tests.yml + package.json)

The action's inline build: ran npm run build --workspaces --if-present, which only builds the example workspace. But example imports @10up/block-components from file:../dist/index.js, which doesn't exist until the root package builds first. Updated the existing build-test-env script to chain root build + workspaces, and pointed the workflow at it (the cypress-io action passes the build: value as a single argv with no shell, so chained && couldn't live inline).

Cypress config loading (tsconfig.json)

When Cypress loads its config, it runs ts-node against the root tsconfig. Two issues blocked it:

  • TS5107 deprecations on esModuleInterop=false and moduleResolution=node10 are warnings under the toolkit build but errors under ts-node. Silenced with ignoreDeprecations: "6.0" (the Microsoft-recommended option).
  • TS5011 fired because ts-node compiles cypress.config.js (and its cypress/plugins/index.js require) in isolation; without an explicit rootDir, ts-node computes the common source directory from a single file and the resolved rootDir doesn't match outDir. Set rootDir: ".".

Cypress test specs (Link.spec.js + registerBlockExtension.spec.js)

Once Cypress could actually run, two specs failed because they clicked the post-publish "View Post" snackbar without first stripping target="_blank" — the click opened a new tab and the test browser stayed on the editor. Follow-up assertions then silently ran against editor markup instead of frontend markup:

  • Link.spec: the editor's RichText <a> has no href attribute, so should('have.attr', 'href', ...) timed out
  • registerBlockExtension.spec: the editor has no "Edit Page" admin-bar link, so cy.contains('Edit Page') timed out

Image.spec already strips target before clicking. Mirroring its pattern fixes both. Verified the underlying frontend rendering is correct by publishing a Link block via wp-cli and inspecting <a href="https://10up.com/">First Link</a> in the rendered HTML.

release_testing (publish-npm.yml)

The job runs npm install -g npm@latest (upgrading to npm 11) before npm install. npm 11's resolver re-evaluates peer entries and writes them out, dirtying the working tree before the subsequent npm version step fails with Git working directory not clean. Switched to npm ci — strict no-op on lockfile state.

Verification (local)

On Node 20.18.1 and Node 22.22.2:

  • npm ci — succeeds, no EUSAGE
  • npm run build — succeeds, dist/index.js produced
  • npm test — Jest passes
  • npm run build-test-env — root + example both build in correct order
  • Cypress's exact ts-node config loads cypress.config.js cleanly — verified by reproducing Cypress's register_ts_node.js options in a Node harness, since Cypress 13/14's binary doesn't run on macOS 26
  • wp-cli publish of a Link block → frontend HTML contains <a href="https://10up.com/">…</a> (confirms the Link spec failure was about the snackbar/tab issue, not product code)

CI status on this PR

Check Status
Jest ✅ pass
ESLint ✅ pass
Analyze (actions / javascript-typescript) ✅ pass
CodeQL ✅ pass
Cypress ✅ pass (35 tests)
release_testing ✅ pass
build (compressed-size) ❌ fail — expected and self-resolving. The action runs npm ci against both PR head and base. The base (develop) still has the broken lockfile until this PR merges, so the action errors on the base-side install. Once this lands on develop, future PRs see a fixed base and the check passes without further changes.

The lockfile drifted out of sync after the security-patch merges in #405,
leaving entries (notably @wordpress/eslint-plugin@18.1.0) that no longer
satisfied the version ranges declared by their parents. Every CI run since
2026-04-01 failed at `npm ci` with `EUSAGE` and dozens of "Missing" lines.

Regenerated via `npm install --package-lock-only` on Node 20.18.1 — adds
the missing transitive entries and prunes stale ones (e.g. stylelint@16.26.1)
without bumping any direct dependency. Build, Jest, and example build all
pass locally.
@colinswinney colinswinney mentioned this pull request May 6, 2026
8 tasks
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

🎉 A new testing version of this package has been published to NPM. You can install it with npm install @10up/block-components@testing-407

The previous regen used npm 11, which silently dropped peer-dep entries
that npm 10 (the version bundled with Node 20/22 in CI) treats as
required. Re-resolved on Node 22.22.2 / npm 10.9.7. Both Node 20 and
Node 22 now `npm ci` cleanly; build and Jest pass.
Now that the lockfile is in sync and `npm ci` succeeds, three CI workflows
hit pre-existing issues that the broken-install pipeline was masking:

- Cypress: the workflow's inline `build:` ran `npm run build --workspaces`,
  which only builds the example workspace. But the example imports
  `@10up/block-components` from `file:../dist/index.js`, which doesn't
  exist until the root package builds first. Build root, then workspaces.

- release_testing: the job runs `npm install -g npm@latest` (upgrading
  to npm 11) before `npm install`. npm 11's resolver re-evaluates peer
  entries and writes them out, dirtying the working tree before the
  subsequent `npm version` step fails with "Git working directory not
  clean". `npm ci` is a strict no-op on lockfile state, so use it.

- compressed-size: the action runs `npm ci` against both PR head and
  base. The base (develop) won't have the lockfile fix until this PR
  merges, so `npm ci` will continue to fail there. Override the action's
  install command to `npm install`, which tolerates lockfile drift.
@colinswinney colinswinney changed the title fix: regenerate package-lock.json to resolve npm ci mismatch fix: restore CI on develop (lockfile drift + workflow regressions) May 6, 2026
cypress-io/github-action@v5 passes the `build:` value as a single
argv (no shell), so `&&` was being captured as a literal positional
arg to the example workspace's build script. Move the chained build
into the existing `build-test-env` script and call that instead, so
the action only ever invokes one command.
cypress.config.js is loaded via ts-node, which compiles it against the
root tsconfig.json. The two TS5107 deprecations on `esModuleInterop`
and `moduleResolution` are warnings under the toolkit build but errors
under ts-node, so Cypress refused to start. The Microsoft-recommended
silencer (`ignoreDeprecations: "6.0"`) keeps both options in their
current behavior until TS 7.0.
When Cypress loads its config, ts-node compiles `cypress/plugins/index.js`
in isolation against the root tsconfig. Without an explicit `rootDir`,
ts-node computes the common source directory from just that single file
('./cypress/plugins'), then fails with TS5011 because the resolved
rootDir doesn't match the configured `outDir`. Setting `rootDir: "."`
fixes the resolution without affecting the toolkit build.
The override was added to mask `npm ci` failing on the **base** branch
(develop's broken lockfile). Once this PR merges, develop's lockfile
will be fixed and the default `npm ci` works again, so the override
is unnecessary and would just permanently loosen `ci` to `install`.
@cypress
Copy link
Copy Markdown

cypress Bot commented May 6, 2026

10up Block Components    Run #1070

Run Properties:  status check passed Passed #1070  •  git commit cb3d01e3be: Remove screenshot artifact accidentally committed in previous push
Project 10up Block Components
Branch Review fix/lockfile-drift
Run status status check passed Passed #1070
Run duration 05m 32s
Commit git commit cb3d01e3be: Remove screenshot artifact accidentally committed in previous push
Committer Colin Swinney
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 35
View all changes introduced in this branch ↗︎

Both specs clicked the post-publish "View Post" snackbar without first
stripping `target="_blank"` from the link, so the click opened a new
tab and the test browser stayed on the editor. That caused the
follow-up assertions to silently fail against editor markup instead
of frontend markup:

- Link.spec: the editor's RichText `<a>` has no `href` attribute, so
  `should('have.attr', 'href', ...)` timed out
- registerBlockExtension.spec: the editor has no "Edit Page" admin-bar
  link, so `cy.contains('Edit Page')` timed out

Image.spec already strips `target` before clicking. Mirroring its
pattern here. Verified the underlying frontend rendering works by
publishing a Link block via wp-cli and inspecting the rendered HTML.
@colinswinney colinswinney self-assigned this May 6, 2026
@colinswinney colinswinney requested a review from fabiankaegy May 6, 2026 10:26
@colinswinney
Copy link
Copy Markdown
Author

@fabiankaegy This was a lot of back and forth to resolve failing checks but I think this should fix all. Once this merges, I'll merge develop back into #406 to hopefully resolve the red checks there. 🤞

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant