Skip to content

[MERGE AFTER 0.10 RELEASE] ci(publish): install only the package being published - #1440

Merged
msluszniak merged 5 commits into
mainfrom
@ms/publish-workflow-install
Sep 8, 2026
Merged

[MERGE AFTER 0.10 RELEASE] ci(publish): install only the package being published#1440
msluszniak merged 5 commits into
mainfrom
@ms/publish-workflow-install

Conversation

@msluszniak

@msluszniak msluszniak commented Sep 8, 2026

Copy link
Copy Markdown
Member

Warning

Do not merge until 0.10.0 is released. This touches the publish path, and there is no reason to carry that risk the day before shipping.

Description

The publish job ran yarn install at the repo root, whose workspaces glob is packages/* + apps/* + apps/legacy/*. Building one package pulled dependencies for eight React Native example apps that are never built.

From the 0.10.0 dry run:

step time
Install monorepo dependencies 164s
Build package (bob + tsc) 19s
everything else 14s

yarn workspaces focus installs only the package's own tree. It is built into Yarn 4, the same command family as the workspaces foreach already used in CI, so no plugin is needed.

packages download
yarn install (root) 1659 597.4 MiB
yarn workspaces focus 709 71.29 MiB

The satellite workflow had the same problem: it passed yarn install --immutable && yarn workspace react-native-executorch prepare as its install command, so each of the three runs paid for the whole monorepo too. Each satellite declares react-native-executorch as a workspace:* devDependency, so focusing on the satellite pulls the core workspace in with it and the core prepare still runs.

Two smaller fixes alongside it:

  • RNET_SKIP_DOWNLOAD=1. The job runs bob and tsc, and the files list excludes third-party/include from the tarball, so the postinstall native download bought nothing and printed two "coreml is iOS-only" warnings on a Linux runner.
  • The install ran twice: once in the workflow, then again in create-package.sh. The script now skips it when RNE_SKIP_INSTALL is set, so a local run is unchanged.

Also: the satellite tarballs shipped a build cache

Found while reading the 0.10.0 bare-fetcher dry run. All three satellites pointed tsBuildInfoFile at ./lib/typescript/tsconfig.tsbuildinfo, inside outDir, and their files list ships all of lib/. So every published tarball carried TypeScript's incremental build cache: 1 of 18 files and roughly a third of the packed bytes, useless to consumers.

Moved it to .cache/, which is outside outDir and already gitignored. Rebuilt and packed locally: 18 files becomes 17, nothing else changes. The core package was never affected, it sets no tsBuildInfoFile.

Also: the dist-tag guard let through every tag it documented

The dist-tag override validated with ^[a-zA-Z][a-zA-Z0-9._-]*$, on the theory that requiring a leading letter ruled out semver. npm's actual rule is that a dist-tag must not parse as a semver range, and the input's own documented example fails it:

input old guard npm
v0.8 (the documented example) passes rejects, parses as >=0.8.0 <0.9.0-0
v0.10.0 passes rejects, parses as 0.10.0
latest, legacy, v0-8 passes fine

The 0.10.0 dry run hit this, failing at npm ten steps in, after the build and pack. Now it asks semver and names a form that works. Verified against 11 inputs: v0.10.0, v0.10, v0.8, 0.8, 1.x and * are rejected with the parsed range in the message; latest, legacy, executorch-nightly, v0-8 and next pass. semver resolves from the repo root under the focused install this branch introduces, and the check runs after that step.

The input description also said "e.g. v0.8" and never said the field is the npm dist-tag rather than the git tag to publish from. Both fixed.

Trade-off

focus does not accept --immutable, so this job stops asserting that the lockfile is in sync. CI already asserts it on every pull request, and a release publishes from a branch that passed. Verified separately that focus leaves yarn.lock untouched, so nothing is silently rewritten.

Introduces a breaking change?

  • Yes
  • No

Type of change

  • Bug fix (change which fixes an issue)
  • New feature (change which adds functionality)
  • Documentation update (improves or adds clarity to existing documentation)
  • Other (chores, tests, code style improvements etc.)

Tested on

  • iOS
  • Android

Testing instructions

Locally, a focused install plus yarn prepare produces a lib/ identical to the one in the published 0.10.0 tarball: 496 files, same paths. The full install measured locally at 1660 packages / 597.08 MiB / 1.6 GB on disk, matching what CI reports. For the satellites, each was verified from a clean node_modules: the core prepare succeeds and every satellite's tsc exits 0. Every static import in src/ and legacy/src/ resolves from the package's own dependencies (@kesha-antonov/react-native-background-downloader is a runtime require() in a try/catch, so tsc never needs it).

The full pack could not be run locally because create-package.sh checks out the phonemis submodule, which needs git-lfs. Before merging, run the core publish workflow from this branch with release-type: latest and dry-run: true, and confirm the tarball is still 1020 files / 1.5 MB (1021 with LICENSE once #1437 lands).

Checklist

  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have updated the documentation accordingly
  • My changes generate no new warnings

The publish job ran yarn install at the repo root, whose workspaces glob
is packages/* + apps/* + apps/legacy/*. Building one package pulled 1659
packages and 597.4 MiB for eight React Native example apps that are never
built: 164s of a 197s job, against 19s for bob and tsc.

yarn workspaces focus installs only this package's tree. It is built into
Yarn 4, the same command family as the workspaces foreach already used in
CI, so no plugin is needed. Measured locally: 709 packages, 71.29 MiB.

Also stopped the postinstall native download (RNET_SKIP_DOWNLOAD), which
this job has no use for since it runs bob and tsc and the files list
excludes third-party/include from the tarball, and stopped the second
install: the workflow installed, then create-package.sh installed again.
@msluszniak msluszniak self-assigned this Sep 8, 2026
@msluszniak msluszniak added the chore PRs that are chores label Sep 8, 2026
@msluszniak msluszniak changed the title ci(publish): install only the package being published [MERGE AFTER 0.10 RELEASE] ci(publish): install only the package being published Sep 8, 2026
The satellite workflow passed 'yarn install --immutable && yarn workspace
react-native-executorch prepare' as its install command, so each of the
three runs paid for the same whole-monorepo install as the core job, plus
the core package's postinstall native download on top.

Each satellite declares react-native-executorch as a workspace:*
devDependency, so focusing on the satellite pulls the core workspace in
with it and the core prepare still runs. Verified locally from a clean
node_modules for all three: core prepare succeeds and each satellite's
tsc exits 0.
All three satellites pointed tsBuildInfoFile at ./lib/typescript inside
outDir, and their files list ships all of lib/, so every published
tarball carried tsconfig.tsbuildinfo: TypeScript's incremental build
cache, useless to consumers and a third of the packed size.

Found while checking the 0.10.0 dry run of the bare fetcher: 18 files,
one of them the build info. Moving it to .cache/, which is already
gitignored and outside outDir, packs 17. The core package was never
affected; it sets no tsBuildInfoFile.
…looks like a version

The override guard required a leading letter, on the theory that this
ruled out semver. It did not. npm's actual rule is that a dist-tag must
not parse as a semver range, and every example this input documented
passes the old check and fails at npm: v0.8 parses as >=0.8.0 <0.9.0-0,
v0.10.0 as 0.10.0. The 0.10.0 dry run hit exactly this, ten steps in,
after building and packing the tarball.

Ask semver instead of approximating it, and say what to use instead. The
package resolves from the repo root under the focused install this branch
introduces, and the check runs after that step.

Also rewrote the input description: it said 'e.g. v0.8', which is one of
the values npm refuses, and did not say the field is the npm dist-tag
rather than the git tag to publish from.
@msluszniak
msluszniak merged commit 3f13b59 into main Sep 8, 2026
5 checks passed
@msluszniak
msluszniak deleted the @ms/publish-workflow-install branch September 8, 2026 09:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore PRs that are chores

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants