-
Notifications
You must be signed in to change notification settings - Fork 666
CONSOLE-4979: Speed up check-patternfly-modules + add dedupe step to CI #15835
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| /* eslint-disable no-console */ | ||
| import * as lockfile from '@yarnpkg/lockfile'; | ||
| import { readFileSync } from 'fs'; | ||
| import { basename } from 'path'; | ||
| import chalk from 'chalk'; | ||
| import * as semver from 'semver'; | ||
|
|
||
| console.log(`Checking ${chalk.yellow('yarn.lock')} for PatternFly module resolutions...`); | ||
|
|
||
| const lockFile = lockfile.parse(readFileSync('yarn.lock', 'utf8')); | ||
|
|
||
| if (lockFile.type !== 'success') { | ||
| console.error(`Failed to parse yarn.lock file: type is ${lockFile.type}`); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| /** List of packages to check along with their required semver ranges */ | ||
| const PKGS_TO_CHECK: Array<{ name: string; semver: string }> = [ | ||
| { name: '@patternfly-5/patternfly', semver: '5.x' }, | ||
| { name: '@patternfly/patternfly', semver: '6.x' }, | ||
| { name: '@patternfly/quickstarts', semver: '6.x' }, | ||
| { name: '@patternfly/react-catalog-view-extension', semver: '6.x' }, | ||
| { name: '@patternfly/react-charts', semver: '8.x' }, | ||
| { name: '@patternfly/react-code-editor', semver: '6.x' }, | ||
| { name: '@patternfly/react-component-groups', semver: '6.x' }, | ||
| { name: '@patternfly/react-core', semver: '6.x' }, | ||
| { name: '@patternfly/react-data-view', semver: '6.x' }, | ||
| { name: '@patternfly/react-icons', semver: '6.x' }, | ||
| { name: '@patternfly/react-log-viewer', semver: '6.x' }, | ||
| { name: '@patternfly/react-styles', semver: '6.x' }, | ||
| { name: '@patternfly/react-table', semver: '6.x' }, | ||
| { name: '@patternfly/react-templates', semver: '6.x' }, | ||
| { name: '@patternfly/react-tokens', semver: '6.x' }, | ||
| { name: '@patternfly/react-topology', semver: '6.x' }, | ||
| { name: '@patternfly/react-user-feedback', semver: '6.x' }, | ||
| { name: '@patternfly/react-virtualized-extension', semver: '6.x' }, | ||
| ]; | ||
|
|
||
| const SCOPES_TO_CHECK = new Set(PKGS_TO_CHECK.map((pkg) => pkg.name.split('/')[0])); | ||
|
|
||
| /** Get the package name and version from a package key in yarn.lock */ | ||
| const parsePackageName = (resolutionKey: string): string => { | ||
| // Precondition: All package names are not substrings of other package names | ||
| // e.g., we cannot have both `my-package` and `my-package-extended` in PKGS_TO_CHECK | ||
| const pkgName = PKGS_TO_CHECK.find((pkg) => resolutionKey.startsWith(pkg.name)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a problem with the current packages, but could we ever have a false positive here if one package name is the prefix of another like
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably..? I think we can fix this problem when we need to, it's hard to properly parse the versions of |
||
|
|
||
| // Ensure that all packages within SCOPES_TO_CHECK are checked | ||
| if (!pkgName) { | ||
| throw new Error( | ||
| `Please update ${chalk.yellow( | ||
| basename(__filename), | ||
| )} to handle this PatternFly package: ${chalk.yellow(resolutionKey)}`, | ||
| ); | ||
| } | ||
|
|
||
| return pkgName.name; | ||
| }; | ||
|
|
||
| /** Map of PatternFly packages to their resolved versions in yarn.lock */ | ||
| const patternflyModules = Object.entries(lockFile.object).reduce( | ||
| (acc, [resolutionKey, resolvedDependency]) => { | ||
| if (SCOPES_TO_CHECK.has(resolutionKey.split('/')[0])) { | ||
| const pkgName = parsePackageName(resolutionKey); | ||
| if (!acc.has(pkgName)) { | ||
| acc.set(pkgName, []); | ||
| } | ||
| acc.get(pkgName).push({ resolvedVersion: resolvedDependency.version }); | ||
| } | ||
|
|
||
| return acc; | ||
| }, | ||
| new Map<string, Array<{ resolvedVersion: string }>>(), | ||
| ); | ||
|
Comment on lines
+60
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Scope filtering should use the parsed package name, not Suggested direction: compute 🤖 Prompt for AI Agents |
||
|
|
||
| let hasResolutionErrors = false; | ||
|
|
||
| for (const pkg of PKGS_TO_CHECK) { | ||
| const resolvedVersions = Array.from( | ||
| new Set((patternflyModules.get(pkg.name) || []).map((v) => v.resolvedVersion)), | ||
| ); | ||
|
|
||
| if (resolvedVersions.length === 0) { | ||
| console.error(`${chalk.red(pkg.name)} has no ${chalk.yellow(pkg.semver)} resolutions`); | ||
| hasResolutionErrors = true; | ||
| } else if (resolvedVersions.length === 1) { | ||
| const resolvedVersion = semver.coerce(resolvedVersions[0]); | ||
|
|
||
| if (!resolvedVersion) { | ||
| console.error( | ||
| `${chalk.red(pkg.name)} has a non-semver coercible resolved version: ${chalk.yellow( | ||
| resolvedVersions[0], | ||
| )}`, | ||
| ); | ||
| hasResolutionErrors = true; | ||
| continue; | ||
| } | ||
|
|
||
| if (!semver.satisfies(resolvedVersion, pkg.semver)) { | ||
| console.error( | ||
| `${chalk.red(pkg.name)} has one resolution ${chalk.yellow( | ||
| resolvedVersions[0], | ||
| )} which does not satisfy ${chalk.yellow(pkg.semver)}`, | ||
| ); | ||
| hasResolutionErrors = true; | ||
| } else { | ||
| console.log( | ||
| `${chalk.green(pkg.name)} has one ${chalk.yellow(pkg.semver)} resolution: ${ | ||
| resolvedVersions[0] | ||
| }`, | ||
| ); | ||
| } | ||
| } else { | ||
| console.error(`${chalk.red(pkg.name)} has multiple resolutions: ${resolvedVersions}`); | ||
| hasResolutionErrors = true; | ||
| } | ||
| } | ||
|
Comment on lines
+77
to
+116
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resolved dependency version may be missing; guard before semver logic Consider filtering falsy versions at collection time (Line 65) or when building 🤖 Prompt for AI Agents |
||
|
|
||
| if (hasResolutionErrors) { | ||
| console.error(`Run ${chalk.yellow('yarn why <pkg-name>')} to inspect module resolution details`); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| console.log(chalk.green('No issues detected')); | ||
Uh oh!
There was an error while loading. Please reload this page.