Skip to content

fix(schematics): pin prerelease installs to the exact version#3709

Open
armando-navarro wants to merge 1 commit into
angular:mainfrom
armando-navarro:fix/pin-prerelease-versions
Open

fix(schematics): pin prerelease installs to the exact version#3709
armando-navarro wants to merge 1 commit into
angular:mainfrom
armando-navarro:fix/pin-prerelease-versions

Conversation

@armando-navarro

Copy link
Copy Markdown
Collaborator

ng add @angular/fire@next records the install with npm's default caret (^21.0.0-rc.0). A prerelease range like that also matches the -canary.<sha> builds published for every merge to main — they sort higher than the RC — so any later fresh install silently replaces the version the user chose with an unreviewed snapshot.

After install, the schematic now pins the workspace's @angular/fire entry to the exact installed version when the recorded spec is a caret or tilde range around a prerelease (and only when the installed version already satisfies that range). Stable ranges, exact versions, and hand-authored range expressions are left untouched. Includes unit specs for the pinning and all leave-alone cases.

Fixes #3708

ng add records the installed package with npm's default caret prefix.
For a stable release that only drifts to reviewed patch releases, but a
prerelease range like ^21.0.0-rc.0 also matches the canary build
published for every merge to main — so a later fresh install could
silently replace the version the user chose with an unreviewed
snapshot.

After install, if the workspace's @angular/fire entry is a caret or
tilde range around a prerelease, rewrite it to the exact installed
version (only when that version already satisfies the range). Stable
ranges and hand-authored range expressions are left untouched.
Comment thread src/schematics/common.ts
try {
return JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json')).toString()).version;
} catch {
return undefined;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: if the file read fails for any reason, readInstalledVersion returns undefined with no log output, so the user gets no indication the pin was skipped. A context.logger.warn in the catch would help debuggability.

Comment thread src/schematics/common.ts
if (!host.exists('package.json')) { return; }
const packageJson = safeReadJSON('package.json', host);

const declaredAngularFireVersion = packageJson.dependencies?.['@angular/fire'];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function only reads from packageJson.dependencies. If @angular/fire somehow ends up in devDependencies, the pin is silently skipped. Unlikely via ng add, but worth a follow-up.

Comment thread src/schematics/common.ts
* directories up. Returns undefined when that layout doesn't hold (e.g. running from source),
* so callers skip pinning instead of failing the schematic.
*/
const readInstalledVersion = () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional/nit, design suggestion: tools/build.ts already stamps values into versions.json at build time, and add/index.ts already imports from it. Adding angularFireVersion there would let you replace the readFileSync/__dirname traversal with a plain JSON import, same pattern already in use and no filesystem-path assumptions.

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.

ng add @angular/fire@next records a caret range that silently drifts to canary builds

2 participants