Skip to content

0.0.14 - #32

Merged
revopushbot merged 13 commits into
mainfrom
0.0.14
Aug 25, 2026
Merged

0.0.14#32
revopushbot merged 13 commits into
mainfrom
0.0.14

Conversation

@revopushbot

Copy link
Copy Markdown
Contributor

Enforce --outputDir layout, drop Windows, and consolidate React-release validation

Why

Diff updates require a release's uploaded package to live under a folder named CodePush — the base-bundle lookup (react-native-utils.ts takeHermesBaseBytecode) resolves the previous bundle via path.basename(outputFolder), and binary extraction (binary-utils.ts) hardcodes a CodePush/ prefix. When --outputDir is omitted we default to os.tmpdir()/CodePush (correct), but a custom --outputDir could be any name, silently breaking diff updates (the base bundle is never found, so no -base-bytecode diff is produced).

This PR fails the release early with a clear message when a custom --outputDir doesn't satisfy that requirement, removes Windows (no longer supported), and consolidates the scattered React-release validation into one place.

What changed

--outputDir validation

  • A custom --outputDir must end in a folder named CodePush (e.g. ./build/CodePush); otherwise the release fails up front with:
    The "--outputDir" path must end with a folder named "CodePush" (e.g. "./build/CodePush"). Received: "...".
  • Applies to release-react and release-expo. release-native is untouched (it nests CodePush/ internally, so its basename is irrelevant).

Drop Windows support

  • release-react now accepts only android / ios.
  • Removed the Windows example and Windows mentions from release-react / release-expo help text in command-parser.ts.
  • Updated the 'Platform must be either …' messages in react-native-utils.ts to drop Windows. (OS-level Windows handling — Git Bash backslashes — is unchanged.)

Consolidated validation (command-executor.ts)

  • Introduced a single validateReactReleaseCommand(command, { resolveEntryFile }) that performs all up-front validation and returns the derived inputs (platform, bundleName, entryFile, projectName): platform check, --outputDir check, React Native project check, and entry-file resolution (skipped for Expo, whose expo export:embed resolves its own entry point). The semver-range check stays in the chain since it needs the async-resolved app version.
  • releaseReact / releaseExpo are now validate → set up folders → run the chain, removing the duplicated platform switch, package.json block, and entry-file logic from both.

Bug fix / hardening (in the consolidation)

  • The old try/catch wrapped the field checks, so the specific "name field not set" / "not a React Native project" errors were swallowed and replaced by the generic "unable to read package.json". The try now wraps only the require, so each error surfaces correctly.
  • Guarded dependencies?.["react-native"] so a package.json with no dependencies reports "not a React Native project" instead of a misleading read error.

Testing

  • npm run build (tsc) passes; lint shows only pre-existing no-unused-vars warnings, none in touched code.
  • release-react MyApp ios --outputDir ./build/wrong → fails immediately with the CodePush message.
  • --outputDir ./build/CodePush (and trailing slash) → proceeds.
  • Omitting --outputDir → still uses the temp CodePush folder.
  • release-react MyApp windows … → rejected with Platform must be either "android" or "ios".

revopushbot and others added 10 commits June 24, 2026 20:40
# Conflicts:
#	package-lock.json
#	package.json
#	script/command-executor.ts
# Conflicts:
#	script/command-executor.ts
Two follow-ups to the 0.0.14 <- main merge, both dependency reductions.

aab-utils read the AAB via jszip, which loads and inflates the ENTIRE
archive into memory to reach one ~2KB entry -- on a 36MB .aab that is 36MB+
of avoidable allocation. Every other zip read in the CLI already goes
through yauzl (file-utils, binary-utils, hash-utils), so this switches the
last holdout: seek the central directory, stream only base/manifest/
AndroidManifest.xml, and break, which closes the file for us. jszip was the
only remaining consumer, so it leaves the tree entirely -- it had been a
transitive dep of aab-parser and was promoted to a direct dep when
aab-parser was removed (ba0c5d9).

Verified against the previous jszip implementation on a synthetic 6-entry
.aab built with aapt2's full field numbering (so the minimal decoder is
still proven to skip fields it does not declare): identical output for both
the string and Buffer overloads, correct entry chosen over deliberate
substring/suffix decoys, unchanged missing-manifest error text, and no file
handles left open after 200 parses.

Separately, body-parser 1.20.5 -> 1.20.6 (GHSA-v422-hmwv-36x6, low, dev-only
via express). In range for express@4.22.2's ~1.20.5; `npm audit fix` reports
this as fixable but is a no-op, so it needed an explicit npm update.

npm audit: 3 low -> 2 low; production deps remain at 0.
The 2 left are diff/mocha, unfixable until mocha 12 leaves rc.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A semantic conflict git could not see, because the two halves live in
different files: the 0.0.14 side added validateReactReleaseCommand(), which
rejects any --outputDir whose basename is not "CodePush" (diff updates
require the package to sit under that folder), while main's new release-size
tests pass outputDir=<tmp>/release-output. Both merged cleanly and the
combination throws before any assertion runs.

Verified: 4 passing at e9e62ab, 0 passing / 4 failing at 87cc2e2, 4 passing
again with the fixture renamed to "CodePush". The validation is the intended
behaviour of this branch, so the fixture adapts to it, not the reverse.

Not caught by CI: the workflow runs only build and lint, and package.json
has no test script, so neither release-size suite executes there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`releaseCommand` is `command` itself -- `const releaseCommand: cli.IReleaseReactCommand = <any>command`
is a type assertion with no runtime effect -- so `releaseCommand.outputDir = outputFolder`
overwrites `command.outputDir` with the resolved path. By the time the chain
reaches its cleanup step, `if (!command.outputDir)` can no longer distinguish
"user passed --outputDir" from "we defaulted to $TMPDIR/CodePush": it is always
truthy, so the temp folder was never removed. The sibling `!command.sourcemapOutput`
guard is unaffected, since sourcemapOutput is never reassigned.

Capture the answer into isTempOutputFolder before the mutation, in both
releaseExpo and releaseReact.

Verified by driving the real releaseReact to completion under the stubs from
test/release-size-flow.ts: without --outputDir the temp folder survived the
release before this change and is gone after it, and a user-supplied
--outputDir is still left alone in both cases. Pre-existing on main as well,
not introduced by the merge -- same check fails there.

Impact was bounded: createEmptyTempReleaseFolder() wipes the folder at the
start of the next release, so this left one release's bundle, assets and
source maps in $TMPDIR between runs rather than growing without limit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
parseAabManifest is the exact counterpart of getIosVersion -- read the
version out of an app binary -- and getIosVersion already lives in
binary-utils, so the .aab path was the only one of the three reading its
version from a separate module. Fold it in and drop script/utils/aab-utils.ts.

binary-utils already imported yauzl and node:stream/consumers for the IPA
reader, so the move deletes those duplicate imports; protobufjs is the only
one it gains. The command-executor <-> binary-utils import cycle is unchanged,
since command-executor already pulled extractMetadataFromAndroid/
extractMetadataFromIOS/getIosVersion from there.

Pure code motion -- no behaviour change. Re-ran the AAB fixture checks against
the new location: identical output for the string and Buffer overloads,
correct entry chosen over decoys, unchanged missing-manifest error text, and
no leaked file handles after 200 parses.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Drop the -rc suffix: 0.0.14-rc.2 -> 0.0.14.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@revopushbot
revopushbot merged commit 8b2db9d into main Aug 25, 2026
2 checks passed
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.

3 participants