feat: exclude @vaadin packages from the minimum frontend package age (#25620) (CP: 25.2) - #25795
Merged
Merged
Conversation
…25620) ## Summary The minimum frontend package age blocks packages that were published very recently. Because the `@vaadin` packages are pinned to the platform version, a build started right after a Vaadin release had no older version to fall back to and failed. Vaadin now tells the package manager to exempt `@vaadin/*` from that check, and warns when the package manager cannot do it. ## What changed **Behavior change:** every build that runs with a minimum frontend package age now gets extra install arguments, and some builds get a new warning. Nothing is added when no age applies. - **npm 11.17.0 and newer:** `--min-release-age-exclude=@vaadin/*` is passed. It exempts the matching packages from both `--min-release-age` and `--before`. - **pnpm 10.17.0 and newer:** `--config.minimum-release-age-exclude=@vaadin/*` is passed. When there is a single pattern it is passed twice, because pnpm reads the setting as a list only when the argument occurs more than once, and pnpm 11 excludes *every* package when the value is a plain string. - **Patterns already configured in `.npmrc` / pnpm config are kept.** A command line value replaces the configured list instead of adding to it, so Vaadin reads the configured patterns and passes them along with `@vaadin/*`. Without this, a project that excludes its own scope silently lost that exclusion. - **bun, older npm, older pnpm:** nothing can be passed, so the build is warned that an install during the first day after a Vaadin release may fail. The warning names the remedy for the package manager in use — upgrade npm to 11.17.0 (first shipped with Node.js 24.19.0), upgrade pnpm to 10.17.0, or, for bun, list the `@vaadin` packages one by one in `minimumReleaseAgeExcludes` in a `bunfig.toml`, since bun matches exact names only. - **bun without a warning:** the project `bunfig.toml` is now read, and the warning is skipped when a `@vaadin` package is an actual value of `minimumReleaseAgeExcludes`. A commented-out line or an unrelated mention is not enough. - **`minimumFrontendPackageAgeDays = 0`:** Vaadin still passes no age argument, but an age that npm or pnpm resolves from its own configuration still applies to the install. That age is now reported as applying, so the `@vaadin` packages are excluded from it instead of being blocked silently. When the package manager itself resolves an age of `0`, nothing applies and nothing is excluded or warned about. - Reading a list-valued setting no longer splits list entries on commas. Only a comma-separated string value is split, because a list entry is complete on its own and may contain a comma of its own in a brace expansion such as `@acme/{ui,core}`. - Javadoc for `minimumFrontendPackageAgeDays` in `Options`, `InitParameters`, `BuildFrontendMojo` and `BuildDevBundleMojo` now documents the exclusion and the required npm/Node.js/pnpm versions. No public or protected API changed. The new methods and the internal `resolveMinimumFrontendPackageAge` rename are package-private. ## Use case A team builds their app with bun, and CI runs a few minutes after a Vaadin release. The install fails because the freshly published `@vaadin` packages are younger than the minimum age, and bun cannot take an exclusion from the command line. The build log now tells them what to do: add the packages they depend on to a `bunfig.toml` next to `package.json`. ```toml [install] minimumReleaseAgeExcludes = ["@vaadin/react-components"] ``` After that the install succeeds, and Vaadin stops printing the warning on every build. ## Test summary | # | Status | What the test verifies | Why it matters | |---|--------|------------------------|----------------| | 1 | ✅ | npm gets `--min-release-age-exclude=@vaadin/*` and no warning | Core fix: a build right after a release must not be blocked | | 2 | ✅ | pnpm gets `--config.minimum-release-age-exclude=@vaadin/*` twice | A single occurrence makes pnpm 11 exclude every package, turning the age check off | | 3 | ✅ | Patterns configured in the package manager are passed along with `@vaadin/*` | A command line value replaces them, so a project would silently lose its own exclusion | | 4 | ✅ | A real pnpm install command contains the exclude argument | Pins that the argument actually reaches the install, not just the resolver | | 5 | ✅ | npm/pnpm too old or bun: no argument, and a warning naming the version or the bunfig setting | The only signal a user gets when the exclusion is impossible | | 6 | ✅ | A `bunfig.toml` listing a `@vaadin` package silences the warning; other packages or a comment do not | A bun project that fixed it must not be nagged; a fake match must not hide a real problem | | 7 | ✅ | With Vaadin configured to `0` and no package manager age: no argument, no exclusion, no warning | A project that opted out must stay fully opted out | | 8 | ✅ | With Vaadin configured to `0` but npm configured with 7 days: the age applies, so `@vaadin/*` is excluded | The silently blocking case this PR fixes | | 9 | ✅ | A package manager age of `0` counts as no age at all | Avoids arguments and warnings when nothing is blocked | | 10 | ✅ | List settings are read from an array and from a comma-separated string; a brace expansion in a list is kept whole; a null/empty key gives an empty list | Splitting `@acme/{ui,core}` would produce two broken patterns | | 11 | ❗ **gap** | `npmSupportsMinReleaseAgeExclude` / `pnpmSupportsMinimumReleaseAgeExclude` comparing a real reported version against 11.17.0 / 10.17.0 | A wrong threshold would pass an unknown argument to an old tool; callers only mock these | - `TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_npm_excludesVaadinPackages` — 1 - `TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_pnpm_excludesVaadinPackagesAsAList` — 2 - `TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_configuredPatterns_areKept` — 3 - `TaskRunPnpmInstallTest.runPnpmInstall_excludesVaadinPackagesFromTheMinimumAge` — 4 - `TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_npmTooOld_warnsInsteadOfExcluding` — 5 - `TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_pnpmTooOld_warnsInsteadOfExcluding` — 5 - `TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_bun_warnsInsteadOfExcluding` — 5 - `TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_bunfigListsThePackages_noWarning` — 6 - `TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_bunfigListsOtherPackages_warns` — 6 - `TaskRunNpmInstallTest.resolveMinimumFrontendPackageAge_zeroConfigured_noArgumentAndNoAge` — 7, 9 - `TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_noAgeApplies_noArgumentOrWarning` — 7 - `TaskRunNpmInstallTest.resolveMinimumFrontendPackageAge_zeroConfiguredWithNpmrcValue_ageStillApplies` — 8 - `TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_npmrcValue_isStillExcludedFrom` — 8 - `TaskRunNpmInstallTest.resolveMinimumFrontendPackageAge_npmrcValueOfZero_noAgeApplies` — 9 - `FrontendToolsTest.getConfiguredSettingValues_listAndCommaSeparatedValue_areRead` — 10 - `FrontendToolsTest.getConfiguredSettingValues_braceExpansionInAList_isKeptTogether` — 10 - `FrontendToolsTest.getConfiguredSettingValues_keyWithoutValue_isEmpty` — 10 Left untested on purpose: the exact wording of the warning (only the key facts are asserted), and the unreadable-`bunfig.toml` path, which just falls back to warning. --------- Co-authored-by: totally-not-ai[bot] <290682512+totally-not-ai[bot]@users.noreply.github.com> Co-authored-by: Artur Signell <artur@vaadin.com>
Contributor
Test Results 1 385 files ±0 1 385 suites ±0 1h 29m 44s ⏱️ - 3m 13s Results for commit 584fcb85. ± Comparison against base commit 795bc8b. ♻️ This comment has been updated with latest results. |
## Summary When a build uses pnpm, pnpm started a second, unwanted install of its own right before running a `postinstall` script, and that install often failed. This change turns that check off, so the script runs. A failing `postinstall` script now also fails the build instead of being silently ignored. Fixes #21662, Fixes #24333 ## What changed **Behavior change:** a `postinstall` script that exits with a non-zero status now fails the build with an `ExecutionFailedException` that names the package and includes the script output. Before, the exit code was thrown away and the build continued as if nothing happened. This affects any project whose `postinstall` script fails — the build now stops instead of continuing with a broken `node_modules`. - The command that runs a `postinstall` script now gets `--config.verify-deps-before-run=false` when pnpm is in use. Before running a script, pnpm checks that `node_modules` is up to date, and that check starts its own install. That install repeats the one Flow just ran, but without the arguments that exempt Vaadin's own packages from the minimum release age and without `--ignore-scripts`. When it failed, the `postinstall` script was never run. - Nothing extra is passed for npm or bun. Neither checks anything before running a script, and bun fails on an argument it does not know. - The postinstall command is now also logged at debug level, next to the install command. No public or protected API changed. The new helper is package-private. ## Test summary | # | Status | What the test verifies | Why it matters | |---|--------|------------------------|----------------| | 1 | ✅ | A `postinstall` script that exits non-zero makes `execute()` throw, and the message names the package and contains what the script printed | This was silently ignored before; without it a broken install looks like a successful build | | 2 | ✅ | The command actually run for pnpm contains `--config.verify-deps-before-run=false` | Pins the fix end-to-end — dropping the call that adds the argument would otherwise keep the suite green | | 3 | ✅ | pnpm options resolve to exactly `--config.verify-deps-before-run=false` | The exact flag spelling is what stops pnpm's extra install | | 4 | ✅ | npm and bun options resolve to no arguments | bun fails on an unknown argument, so passing it would break every bun build | - `TaskRunNpmInstallTest.runNpmInstall_postInstallFails_buildFailsWithTheScriptOutput` → 1 (inherited by `TaskRunPnpmInstallTest`, so it runs for npm and pnpm) - `TaskRunPnpmInstallTest.runPnpmInstall_postinstallDoesNotVerifyTheDependencies` → 2 - `TaskRunNpmInstallTest.postinstallArguments_pnpm_doesNotVerifyTheDependencies` → 3 - `TaskRunNpmInstallTest.postinstallArguments_npmAndBun_needNone` → 4 Left untested on purpose: the happy path — a `postinstall` script that succeeds and lets the build pass — is already pinned by the existing `runNpmInstall_postInstall_*` tests. There is no end-to-end bun test class, so bun is covered at the argument level only (row 4). --------- Co-authored-by: totally-not-ai[bot] <290682512+totally-not-ai[bot]@users.noreply.github.com>
|
ZheSun88
approved these changes
Sep 18, 2026
Collaborator
|
This ticket/PR has been released with Vaadin 25.2.9. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
A build that started right after a Vaadin release could fail, because the minimum frontend package age blocks packages that were published a moment ago. Vaadin now tells npm and pnpm to exempt
@vaadin/*from that check, and warns when the package manager cannot do it. The PR also stops pnpm from starting a second, failing install of its own before apostinstallscript.What changed
Behavior change 1: every build that runs with a minimum frontend package age now gets extra install arguments, and some builds get a new warning. Nothing is added when no age applies. This affects all users who leave the age check on (the default).
Behavior change 2: a
postinstallscript that exits with a non-zero status now fails the build with anExecutionFailedExceptionthat names the package and includes the script output. Before, the exit code was thrown away and the build continued as if nothing happened. This affects any project whosepostinstallscript fails — the build now stops instead of continuing with a brokennode_modules.Excluding the Vaadin packages:
--min-release-age-exclude=@vaadin/*is passed. It exempts the matching packages from both--min-release-ageand--before.--config.minimum-release-age-exclude=@vaadin/*is passed. A single pattern is passed twice, because pnpm reads the setting as a list only when the argument occurs more than once, and pnpm 11 excludes every package when the value is a plain string..npmrc/ pnpm config are kept. A command line value replaces the configured list instead of adding to it, so Vaadin reads the configured patterns and passes them along with@vaadin/*. Without this, a project that excludes its own scope silently lost that exclusion.@vaadinpackages one by one inminimumReleaseAgeExcludesin abunfig.toml, since bun matches exact names only.bunfig.tomlis now read, and the warning is skipped when a@vaadinpackage is an actual value ofminimumReleaseAgeExcludes. A commented-out line or an unrelated mention is not enough.minimumFrontendPackageAgeDays = 0: Vaadin still passes no age argument, but an age that npm or pnpm resolves from its own configuration still applies to the install. That age is now reported as applying, so the@vaadinpackages are excluded from it instead of being blocked silently. When the package manager itself resolves an age of0, nothing applies and nothing is excluded or warned about.@acme/{ui,core}.minimumFrontendPackageAgeDaysinOptions,InitParameters,BuildFrontendMojoandBuildDevBundleMojonow documents the exclusion and the required npm/Node.js/pnpm versions.The pnpm
postinstallfix:postinstallscript now gets--config.verify-deps-before-run=falsewhen pnpm is in use. Before running a script, pnpm checks thatnode_modulesis up to date, and that check starts its own install. That install repeats the one Flow just ran, but without the arguments that exempt the Vaadin packages from the minimum release age and without--ignore-scripts. When it failed, thepostinstallscript was never run.No public or protected API changed. The new methods are package-private.
Use case
A team builds their app with bun, and CI runs a few minutes after a Vaadin release. The install fails because the freshly published
@vaadinpackages are younger than the minimum age, and bun cannot take an exclusion from the command line. The build log now tells them what to do: add the packages they depend on to abunfig.tomlnext topackage.json.After that the install succeeds, and Vaadin stops printing the warning on every build.
Test summary
--min-release-age-exclude=@vaadin/*and no warning--config.minimum-release-age-exclude=@vaadin/*twice@vaadin/*bunfig.tomllisting a@vaadinpackage silences the warning; other packages or a comment do not0and no package manager age: no argument, no exclusion, no warning0but npm configured with 7 days: the age applies, so@vaadin/*is excluded0counts as no age at all@acme/{ui,core}would produce two broken patternspostinstallscript that exits non-zero makesexecute()throw, and the message names the package and contains what the script printed--config.verify-deps-before-run=falsenpmSupportsMinReleaseAgeExclude/pnpmSupportsMinimumReleaseAgeExcludecomparing a real reported version against 11.17.0 / 10.17.0TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_npm_excludesVaadinPackages→ 1TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_pnpm_excludesVaadinPackagesAsAList→ 2TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_configuredPatterns_areKept→ 3TaskRunPnpmInstallTest.runPnpmInstall_excludesVaadinPackagesFromTheMinimumAge→ 4TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_npmTooOld_warnsInsteadOfExcluding→ 5TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_pnpmTooOld_warnsInsteadOfExcluding→ 5TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_bun_warnsInsteadOfExcluding→ 5TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_bunfigListsThePackages_noWarning→ 6TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_bunfigListsOtherPackages_warns→ 6TaskRunNpmInstallTest.resolveMinimumFrontendPackageAge_zeroConfigured_noArgumentAndNoAge→ 7, 9TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_noAgeApplies_noArgumentOrWarning→ 7TaskRunNpmInstallTest.resolveMinimumFrontendPackageAge_zeroConfiguredWithNpmrcValue_ageStillApplies→ 8TaskRunNpmInstallTest.minimumFrontendPackageAgeExclude_npmrcValue_isStillExcludedFrom→ 8TaskRunNpmInstallTest.resolveMinimumFrontendPackageAge_npmrcValueOfZero_noAgeApplies→ 9FrontendToolsTest.getConfiguredSettingValues_listAndCommaSeparatedValue_areRead→ 10FrontendToolsTest.getConfiguredSettingValues_braceExpansionInAList_isKeptTogether→ 10FrontendToolsTest.getConfiguredSettingValues_keyWithoutValue_isEmpty→ 10TaskRunNpmInstallTest.runNpmInstall_postInstallFails_buildFailsWithTheScriptOutput→ 11 (inherited byTaskRunPnpmInstallTest, so it runs for npm and pnpm)TaskRunPnpmInstallTest.runPnpmInstall_postinstallDoesNotVerifyTheDependencies→ 12TaskRunNpmInstallTest.postinstallArguments_pnpm_doesNotVerifyTheDependencies→ 13TaskRunNpmInstallTest.postinstallArguments_npmAndBun_needNone→ 13Left untested on purpose: the exact wording of the warning (only the key facts are asserted), the unreadable-
bunfig.tomlpath, which just falls back to warning, and the happy path of apostinstallscript that succeeds, which the existingrunNpmInstall_postInstall_*tests already pin. There is no end-to-end bun test class, so bun is covered at the argument level only.