@code-pushup/ci 0.56.0 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +27 -8
  2. package/package.json +10 -8
  3. package/src/index.d.ts +4 -4
  4. package/src/index.js +3 -0
  5. package/src/index.js.map +1 -0
  6. package/src/lib/cli/commands/collect.d.ts +2 -3
  7. package/src/lib/cli/commands/collect.js +16 -0
  8. package/src/lib/cli/commands/collect.js.map +1 -0
  9. package/src/lib/cli/commands/compare.d.ts +2 -3
  10. package/src/lib/cli/commands/compare.js +20 -0
  11. package/src/lib/cli/commands/compare.js.map +1 -0
  12. package/src/lib/cli/commands/merge-diffs.d.ts +2 -3
  13. package/src/lib/cli/commands/merge-diffs.js +23 -0
  14. package/src/lib/cli/commands/merge-diffs.js.map +1 -0
  15. package/src/lib/cli/commands/print-config.d.ts +2 -2
  16. package/src/lib/cli/commands/print-config.js +26 -0
  17. package/src/lib/cli/commands/print-config.js.map +1 -0
  18. package/src/lib/cli/context.d.ts +3 -5
  19. package/src/lib/cli/context.js +9 -0
  20. package/src/lib/cli/context.js.map +1 -0
  21. package/src/lib/cli/index.d.ts +6 -6
  22. package/src/lib/cli/index.js +7 -0
  23. package/src/lib/cli/index.js.map +1 -0
  24. package/src/lib/cli/persist.d.ts +5 -26
  25. package/src/lib/cli/persist.js +24 -0
  26. package/src/lib/cli/persist.js.map +1 -0
  27. package/src/lib/comment.d.ts +1 -1
  28. package/src/lib/comment.js +29 -0
  29. package/src/lib/comment.js.map +1 -0
  30. package/src/lib/constants.d.ts +1 -1
  31. package/src/lib/constants.js +15 -0
  32. package/src/lib/constants.js.map +1 -0
  33. package/src/lib/git.js +99 -0
  34. package/src/lib/git.js.map +1 -0
  35. package/src/lib/issues.d.ts +1 -1
  36. package/src/lib/issues.js +96 -0
  37. package/src/lib/issues.js.map +1 -0
  38. package/src/lib/models.d.ts +9 -11
  39. package/src/lib/models.js +2 -0
  40. package/src/lib/models.js.map +1 -0
  41. package/src/lib/monorepo/detect-tool.d.ts +1 -1
  42. package/src/lib/monorepo/detect-tool.js +11 -0
  43. package/src/lib/monorepo/detect-tool.js.map +1 -0
  44. package/src/lib/monorepo/handlers/index.d.ts +1 -1
  45. package/src/lib/monorepo/handlers/index.js +20 -0
  46. package/src/lib/monorepo/handlers/index.js.map +1 -0
  47. package/src/lib/monorepo/handlers/npm.d.ts +1 -1
  48. package/src/lib/monorepo/handlers/npm.js +29 -0
  49. package/src/lib/monorepo/handlers/npm.js.map +1 -0
  50. package/src/lib/monorepo/handlers/nx.d.ts +1 -1
  51. package/src/lib/monorepo/handlers/nx.js +62 -0
  52. package/src/lib/monorepo/handlers/nx.js.map +1 -0
  53. package/src/lib/monorepo/handlers/pnpm.d.ts +1 -1
  54. package/src/lib/monorepo/handlers/pnpm.js +47 -0
  55. package/src/lib/monorepo/handlers/pnpm.js.map +1 -0
  56. package/src/lib/monorepo/handlers/turbo.d.ts +1 -1
  57. package/src/lib/monorepo/handlers/turbo.js +48 -0
  58. package/src/lib/monorepo/handlers/turbo.js.map +1 -0
  59. package/src/lib/monorepo/handlers/yarn.d.ts +1 -1
  60. package/src/lib/monorepo/handlers/yarn.js +44 -0
  61. package/src/lib/monorepo/handlers/yarn.js.map +1 -0
  62. package/src/lib/monorepo/index.d.ts +2 -2
  63. package/src/lib/monorepo/index.js +3 -0
  64. package/src/lib/monorepo/index.js.map +1 -0
  65. package/src/lib/monorepo/list-projects.d.ts +9 -3
  66. package/src/lib/monorepo/list-projects.js +99 -0
  67. package/src/lib/monorepo/list-projects.js.map +1 -0
  68. package/src/lib/monorepo/packages.js +50 -0
  69. package/src/lib/monorepo/packages.js.map +1 -0
  70. package/src/lib/monorepo/tools.d.ts +6 -0
  71. package/src/lib/monorepo/tools.js +5 -0
  72. package/src/lib/monorepo/tools.js.map +1 -0
  73. package/src/lib/run-monorepo.d.ts +3 -0
  74. package/src/lib/run-monorepo.js +141 -0
  75. package/src/lib/run-monorepo.js.map +1 -0
  76. package/src/lib/run-standalone.d.ts +3 -0
  77. package/src/lib/run-standalone.js +19 -0
  78. package/src/lib/run-standalone.js.map +1 -0
  79. package/src/lib/run-utils.d.ts +45 -0
  80. package/src/lib/run-utils.js +158 -0
  81. package/src/lib/run-utils.js.map +1 -0
  82. package/src/lib/run.d.ts +1 -1
  83. package/src/lib/run.js +24 -0
  84. package/src/lib/run.js.map +1 -0
  85. package/index.js +0 -1742
@@ -0,0 +1,96 @@
1
+ import { adjustFileName, adjustLine, isFileChanged, } from './git.js';
2
+ export function filterRelevantIssues({ currReport, prevReport, reportsDiff, changedFiles, }) {
3
+ const auditsWithPlugin = [
4
+ ...reportsDiff.audits.changed,
5
+ ...reportsDiff.audits.added,
6
+ ]
7
+ .map((auditLink) => {
8
+ const plugin = currReport.plugins.find(({ slug }) => slug === auditLink.plugin.slug);
9
+ const audit = plugin?.audits.find(({ slug }) => slug === auditLink.slug);
10
+ return plugin && audit && [plugin, audit];
11
+ })
12
+ .filter((ctx) => ctx != null);
13
+ const issues = auditsWithPlugin.flatMap(([plugin, audit]) => getAuditIssues(audit, plugin));
14
+ const prevIssues = prevReport.plugins.flatMap(plugin => plugin.audits.flatMap(audit => getAuditIssues(audit, plugin)));
15
+ return issues
16
+ .filter(issue => isFileChanged(changedFiles, issue.source.file) &&
17
+ !prevIssues.some(prevIssue => issuesMatch(prevIssue, issue, changedFiles)))
18
+ .sort(createIssuesSortCompareFn(currReport));
19
+ }
20
+ function getAuditIssues(audit, plugin) {
21
+ return (audit.details?.issues
22
+ ?.filter((issue) => issue.source?.file != null)
23
+ .map(issue => ({ ...issue, audit, plugin })) ?? []);
24
+ }
25
+ export function issuesMatch(prev, curr, changedFiles) {
26
+ return (prev.plugin.slug === curr.plugin.slug &&
27
+ prev.audit.slug === curr.audit.slug &&
28
+ prev.severity === curr.severity &&
29
+ removeDigits(prev.message) === removeDigits(curr.message) &&
30
+ adjustFileName(changedFiles, prev.source.file) === curr.source.file &&
31
+ positionsMatch(prev.source, curr.source, changedFiles));
32
+ }
33
+ function removeDigits(message) {
34
+ return message.replace(/\d+/g, '');
35
+ }
36
+ function positionsMatch(prev, curr, changedFiles) {
37
+ if (!hasPosition(prev) || !hasPosition(curr)) {
38
+ return hasPosition(prev) === hasPosition(curr);
39
+ }
40
+ return (adjustedStartLinesMatch(prev, curr, changedFiles) ||
41
+ adjustedLineSpansMatch(prev, curr, changedFiles));
42
+ }
43
+ function hasPosition(source) {
44
+ return source.position != null;
45
+ }
46
+ function adjustedStartLinesMatch(prev, curr, changedFiles) {
47
+ return (adjustLine(changedFiles, prev.file, prev.position.startLine) ===
48
+ curr.position.startLine);
49
+ }
50
+ function adjustedLineSpansMatch(prev, curr, changedFiles) {
51
+ if (prev.position?.endLine == null || curr.position?.endLine == null) {
52
+ return false;
53
+ }
54
+ const prevLineCount = prev.position.endLine - prev.position.startLine;
55
+ const currLineCount = curr.position.endLine - curr.position.startLine;
56
+ const currStartLineOffset = adjustLine(changedFiles, curr.file, curr.position.startLine) -
57
+ curr.position.startLine;
58
+ return prevLineCount === currLineCount - currStartLineOffset;
59
+ }
60
+ function createIssuesSortCompareFn(report) {
61
+ return (a, b) => getAuditImpactValue(b, report) - getAuditImpactValue(a, report);
62
+ }
63
+ export function getAuditImpactValue({ audit, plugin }, report) {
64
+ if (!report.categories) {
65
+ return 0;
66
+ }
67
+ return report.categories
68
+ .map((category) => {
69
+ const weights = category.refs.map((ref) => {
70
+ if (ref.plugin !== plugin.slug) {
71
+ return 0;
72
+ }
73
+ switch (ref.type) {
74
+ case 'audit':
75
+ return ref.slug === audit.slug ? ref.weight : 0;
76
+ case 'group':
77
+ return calculateGroupImpact(ref, audit, report);
78
+ }
79
+ });
80
+ return (weights.reduce((acc, weight) => acc + weight, 0) /
81
+ category.refs.reduce((acc, { weight }) => acc + weight, 0));
82
+ })
83
+ .reduce((acc, value) => acc + value, 0);
84
+ }
85
+ export function calculateGroupImpact(ref, audit, report) {
86
+ const group = report.plugins
87
+ .find(({ slug }) => slug === ref.plugin)
88
+ ?.groups?.find(({ slug }) => slug === ref.slug);
89
+ if (!group?.refs.length) {
90
+ return 0;
91
+ }
92
+ const groupRatio = (group.refs.find(({ slug }) => slug === audit.slug)?.weight ?? 0) /
93
+ group.refs.reduce((acc, { weight }) => acc + weight, 0);
94
+ return ref.weight * groupRatio;
95
+ }
96
+ //# sourceMappingURL=issues.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues.js","sourceRoot":"","sources":["../../../../../packages/ci/src/lib/issues.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,13 @@
1
- import type { SourceFileIssue } from './issues';
2
- import type { MonorepoTool } from './monorepo';
1
+ import type { Format } from '@code-pushup/models';
2
+ import type { SourceFileIssue } from './issues.js';
3
+ import type { MonorepoTool } from './monorepo/index.js';
3
4
  /**
4
5
  * Customization options for {@link runInCI}
5
6
  * @see https://github.com/code-pushup/cli/tree/main/packages/ci#options
6
7
  */
7
8
  export type Options = {
8
9
  monorepo?: boolean | MonorepoTool;
10
+ parallel?: boolean | number;
9
11
  projects?: string[] | null;
10
12
  task?: string;
11
13
  nxProjectsFilter?: string | string[];
@@ -16,7 +18,6 @@ export type Options = {
16
18
  debug?: boolean;
17
19
  detectNewIssues?: boolean;
18
20
  logger?: Logger;
19
- output?: string;
20
21
  };
21
22
  /**
22
23
  * {@link Options} with filled-in defaults.
@@ -82,23 +83,20 @@ export type MonorepoRunResult = {
82
83
  mode: 'monorepo';
83
84
  projects: ProjectRunResult[];
84
85
  commentId?: number;
85
- diffArtifact?: ArtifactData;
86
+ diffPath?: string;
86
87
  };
87
88
  /**
88
89
  * Result of {@link runInCI} for a single project
89
90
  */
90
91
  export type ProjectRunResult = {
91
92
  name: string;
92
- artifacts: {
93
- report: ArtifactData;
94
- diff?: ArtifactData;
93
+ files: {
94
+ report: OutputFiles;
95
+ diff?: OutputFiles;
95
96
  };
96
97
  newIssues?: SourceFileIssue[];
97
98
  };
98
99
  /**
99
100
  * Paths to output files from {@link runInCI}, for uploading as job artifact
100
101
  */
101
- export type ArtifactData = {
102
- rootDir: string;
103
- files: string[];
104
- };
102
+ export type OutputFiles = Record<Format, string>;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../../../../packages/ci/src/lib/models.ts"],"names":[],"mappings":""}
@@ -1,2 +1,2 @@
1
- import type { MonorepoHandlerOptions, MonorepoTool } from './tools';
1
+ import type { MonorepoHandlerOptions, MonorepoTool } from './tools.js';
2
2
  export declare function detectMonorepoTool(options: MonorepoHandlerOptions): Promise<MonorepoTool | null>;
@@ -0,0 +1,11 @@
1
+ import { MONOREPO_TOOL_HANDLERS } from './handlers/index.js';
2
+ export async function detectMonorepoTool(options) {
3
+ // eslint-disable-next-line functional/no-loop-statements
4
+ for (const handler of MONOREPO_TOOL_HANDLERS) {
5
+ if (await handler.isConfigured(options)) {
6
+ return handler.tool;
7
+ }
8
+ }
9
+ return null;
10
+ }
11
+ //# sourceMappingURL=detect-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-tool.js","sourceRoot":"","sources":["../../../../../../packages/ci/src/lib/monorepo/detect-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAG7D,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAA+B;IAE/B,yDAAyD;IACzD,KAAK,MAAM,OAAO,IAAI,sBAAsB,EAAE,CAAC;QAC7C,IAAI,MAAM,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;YACxC,OAAO,OAAO,CAAC,IAAI,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -1,3 +1,3 @@
1
- import type { MonorepoTool, MonorepoToolHandler } from '../tools';
1
+ import type { MonorepoTool, MonorepoToolHandler } from '../tools.js';
2
2
  export declare const MONOREPO_TOOL_HANDLERS: MonorepoToolHandler[];
3
3
  export declare function getToolHandler(tool: MonorepoTool): MonorepoToolHandler;
@@ -0,0 +1,20 @@
1
+ import { npmHandler } from './npm.js';
2
+ import { nxHandler } from './nx.js';
3
+ import { pnpmHandler } from './pnpm.js';
4
+ import { turboHandler } from './turbo.js';
5
+ import { yarnHandler } from './yarn.js';
6
+ export const MONOREPO_TOOL_HANDLERS = [
7
+ nxHandler,
8
+ turboHandler,
9
+ yarnHandler,
10
+ pnpmHandler,
11
+ npmHandler,
12
+ ];
13
+ export function getToolHandler(tool) {
14
+ const matchedHandler = MONOREPO_TOOL_HANDLERS.find(handler => handler.tool === tool);
15
+ if (!matchedHandler) {
16
+ throw new Error(`No handler available for monorepo tool "${tool}"`);
17
+ }
18
+ return matchedHandler;
19
+ }
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../packages/ci/src/lib/monorepo/handlers/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,SAAS;IACT,YAAY;IACZ,WAAW;IACX,WAAW;IACX,UAAU;CACX,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,IAAkB;IAC/C,MAAM,cAAc,GAAG,sBAAsB,CAAC,IAAI,CAChD,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,IAAI,CACjC,CAAC;IACF,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,2CAA2C,IAAI,GAAG,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC"}
@@ -1,2 +1,2 @@
1
- import type { MonorepoToolHandler } from '../tools';
1
+ import type { MonorepoToolHandler } from '../tools.js';
2
2
  export declare const npmHandler: MonorepoToolHandler;
@@ -0,0 +1,29 @@
1
+ import path from 'node:path';
2
+ import { fileExists } from '@code-pushup/utils';
3
+ import { hasCodePushUpDependency, hasScript, hasWorkspacesEnabled, listWorkspaces, } from '../packages.js';
4
+ export const npmHandler = {
5
+ tool: 'npm',
6
+ async isConfigured(options) {
7
+ return ((await fileExists(path.join(options.cwd, 'package-lock.json'))) &&
8
+ (await hasWorkspacesEnabled(options.cwd)));
9
+ },
10
+ async listProjects(options) {
11
+ const { workspaces, rootPackageJson } = await listWorkspaces(options.cwd);
12
+ return workspaces
13
+ .filter(({ packageJson }) => hasScript(packageJson, options.task) ||
14
+ hasCodePushUpDependency(packageJson) ||
15
+ hasCodePushUpDependency(rootPackageJson))
16
+ .map(({ name, directory, packageJson }) => ({
17
+ name,
18
+ directory,
19
+ bin: hasScript(packageJson, options.task)
20
+ ? `npm run ${options.task} --`
21
+ : `npm exec ${options.task} --`,
22
+ }));
23
+ },
24
+ createRunManyCommand(options) {
25
+ // neither parallel execution nor projects filter are supported in NPM workspaces
26
+ return `npm run ${options.task} --workspaces --if-present --`;
27
+ },
28
+ };
29
+ //# sourceMappingURL=npm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"npm.js","sourceRoot":"","sources":["../../../../../../../packages/ci/src/lib/monorepo/handlers/npm.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,uBAAuB,EACvB,SAAS,EACT,oBAAoB,EACpB,cAAc,GACf,MAAM,gBAAgB,CAAC;AAGxB,MAAM,CAAC,MAAM,UAAU,GAAwB;IAC7C,IAAI,EAAE,KAAK;IAEX,KAAK,CAAC,YAAY,CAAC,OAAO;QACxB,OAAO,CACL,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC,CAAC;YAC/D,CAAC,MAAM,oBAAoB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAC1C,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAO;QACxB,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC1E,OAAO,UAAU;aACd,MAAM,CACL,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAClB,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC;YACpC,uBAAuB,CAAC,WAAW,CAAC;YACpC,uBAAuB,CAAC,eAAe,CAAC,CAC3C;aACA,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;YAC1C,IAAI;YACJ,SAAS;YACT,GAAG,EAAE,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC;gBACvC,CAAC,CAAC,WAAW,OAAO,CAAC,IAAI,KAAK;gBAC9B,CAAC,CAAC,YAAY,OAAO,CAAC,IAAI,KAAK;SAClC,CAAC,CAAC,CAAC;IACR,CAAC;IAED,oBAAoB,CAAC,OAAO;QAC1B,iFAAiF;QACjF,OAAO,WAAW,OAAO,CAAC,IAAI,+BAA+B,CAAC;IAChE,CAAC;CACF,CAAC"}
@@ -1,2 +1,2 @@
1
- import type { MonorepoToolHandler } from '../tools';
1
+ import type { MonorepoToolHandler } from '../tools.js';
2
2
  export declare const nxHandler: MonorepoToolHandler;
@@ -0,0 +1,62 @@
1
+ import path from 'node:path';
2
+ import { executeProcess, fileExists, stringifyError, toArray, } from '@code-pushup/utils';
3
+ export const nxHandler = {
4
+ tool: 'nx',
5
+ async isConfigured(options) {
6
+ return ((await fileExists(path.join(options.cwd, 'nx.json'))) &&
7
+ (await executeProcess({
8
+ command: 'npx',
9
+ args: ['nx', 'report'],
10
+ cwd: options.cwd,
11
+ observer: options.observer,
12
+ ignoreExitCode: true,
13
+ })).code === 0);
14
+ },
15
+ async listProjects(options) {
16
+ const { stdout } = await executeProcess({
17
+ command: 'npx',
18
+ args: [
19
+ 'nx',
20
+ 'show',
21
+ 'projects',
22
+ ...toArray(options.nxProjectsFilter).map(arg => arg.replaceAll('{task}', options.task)),
23
+ '--json',
24
+ ],
25
+ cwd: options.cwd,
26
+ observer: options.observer,
27
+ });
28
+ const projects = parseProjects(stdout);
29
+ return projects.toSorted().map(project => ({
30
+ name: project,
31
+ bin: `npx nx run ${project}:${options.task} --`,
32
+ }));
33
+ },
34
+ createRunManyCommand(options, projects) {
35
+ const projectNames = projects.only ?? projects.all.map(({ name }) => name);
36
+ return [
37
+ 'npx',
38
+ 'nx',
39
+ 'run-many',
40
+ `--targets=${options.task}`,
41
+ `--parallel=${options.parallel}`,
42
+ `--projects=${projectNames.join(',')}`,
43
+ '--',
44
+ ].join(' ');
45
+ },
46
+ };
47
+ function parseProjects(stdout) {
48
+ // eslint-disable-next-line functional/no-let
49
+ let json;
50
+ try {
51
+ json = JSON.parse(stdout);
52
+ }
53
+ catch (error) {
54
+ throw new Error(`Invalid non-JSON output from 'nx show projects' - ${stringifyError(error)}`);
55
+ }
56
+ if (Array.isArray(json) &&
57
+ json.every((item) => typeof item === 'string')) {
58
+ return json;
59
+ }
60
+ throw new Error(`Invalid JSON output from 'nx show projects', expected array of strings, received ${JSON.stringify(json)}`);
61
+ }
62
+ //# sourceMappingURL=nx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nx.js","sourceRoot":"","sources":["../../../../../../../packages/ci/src/lib/monorepo/handlers/nx.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,cAAc,EACd,UAAU,EACV,cAAc,EACd,OAAO,GACR,MAAM,oBAAoB,CAAC;AAG5B,MAAM,CAAC,MAAM,SAAS,GAAwB;IAC5C,IAAI,EAAE,IAAI;IAEV,KAAK,CAAC,YAAY,CAAC,OAAO;QACxB,OAAO,CACL,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC;YACrD,CACE,MAAM,cAAc,CAAC;gBACnB,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC;gBACtB,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,cAAc,EAAE,IAAI;aACrB,CAAC,CACH,CAAC,IAAI,KAAK,CAAC,CACb,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAO;QACxB,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,cAAc,CAAC;YACtC,OAAO,EAAE,KAAK;YACd,IAAI,EAAE;gBACJ,IAAI;gBACJ,MAAM;gBACN,UAAU;gBACV,GAAG,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAC7C,GAAG,CAAC,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CACvC;gBACD,QAAQ;aACT;YACD,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;QACvC,OAAO,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACzC,IAAI,EAAE,OAAO;YACb,GAAG,EAAE,cAAc,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK;SAChD,CAAC,CAAC,CAAC;IACN,CAAC;IAED,oBAAoB,CAAC,OAAO,EAAE,QAAQ;QACpC,MAAM,YAAY,GAChB,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QACxD,OAAO;YACL,KAAK;YACL,IAAI;YACJ,UAAU;YACV,aAAa,OAAO,CAAC,IAAI,EAAE;YAC3B,cAAc,OAAO,CAAC,QAAQ,EAAE;YAChC,cAAc,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;YACtC,IAAI;SACL,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACd,CAAC;CACF,CAAC;AAEF,SAAS,aAAa,CAAC,MAAc;IACnC,6CAA6C;IAC7C,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,qDAAqD,cAAc,CACjE,KAAK,CACN,EAAE,CACJ,CAAC;IACJ,CAAC;IAED,IACE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QACnB,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,EAC9D,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,IAAI,KAAK,CACb,oFAAoF,IAAI,CAAC,SAAS,CAChG,IAAI,CACL,EAAE,CACJ,CAAC;AACJ,CAAC"}
@@ -1,2 +1,2 @@
1
- import type { MonorepoToolHandler } from '../tools';
1
+ import type { MonorepoToolHandler } from '../tools.js';
2
2
  export declare const pnpmHandler: MonorepoToolHandler;
@@ -0,0 +1,47 @@
1
+ import path from 'node:path';
2
+ import * as YAML from 'yaml';
3
+ import { fileExists, readTextFile } from '@code-pushup/utils';
4
+ import { hasCodePushUpDependency, hasScript, listPackages, readRootPackageJson, } from '../packages.js';
5
+ const WORKSPACE_FILE = 'pnpm-workspace.yaml';
6
+ export const pnpmHandler = {
7
+ tool: 'pnpm',
8
+ async isConfigured(options) {
9
+ return ((await fileExists(path.join(options.cwd, WORKSPACE_FILE))) &&
10
+ (await fileExists(path.join(options.cwd, 'package.json'))));
11
+ },
12
+ async listProjects(options) {
13
+ const yaml = await readTextFile(path.join(options.cwd, WORKSPACE_FILE));
14
+ const workspace = YAML.parse(yaml);
15
+ const packages = await listPackages(options.cwd, workspace.packages);
16
+ const rootPackageJson = await readRootPackageJson(options.cwd);
17
+ return packages
18
+ .filter(({ packageJson }) => hasScript(packageJson, options.task) ||
19
+ hasCodePushUpDependency(packageJson) ||
20
+ hasCodePushUpDependency(rootPackageJson))
21
+ .map(({ name, directory, packageJson }) => ({
22
+ name,
23
+ directory,
24
+ bin: hasScript(packageJson, options.task)
25
+ ? `pnpm run ${options.task}`
26
+ : `pnpm exec ${options.task}`,
27
+ }));
28
+ },
29
+ createRunManyCommand(options, projects) {
30
+ // https://pnpm.io/cli/recursive#--workspace-concurrency
31
+ const workspaceConcurrency = options.parallel === true
32
+ ? null
33
+ : options.parallel === false
34
+ ? 1
35
+ : options.parallel;
36
+ return [
37
+ 'pnpm',
38
+ '--recursive',
39
+ ...(workspaceConcurrency == null
40
+ ? []
41
+ : [`--workspace-concurrency=${workspaceConcurrency}`]),
42
+ ...(projects.only?.map(project => `--filter=${project}`) ?? []),
43
+ options.task,
44
+ ].join(' ');
45
+ },
46
+ };
47
+ //# sourceMappingURL=pnpm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pnpm.js","sourceRoot":"","sources":["../../../../../../../packages/ci/src/lib/monorepo/handlers/pnpm.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACL,uBAAuB,EACvB,SAAS,EACT,YAAY,EACZ,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAGxB,MAAM,cAAc,GAAG,qBAAqB,CAAC;AAE7C,MAAM,CAAC,MAAM,WAAW,GAAwB;IAC9C,IAAI,EAAE,MAAM;IAEZ,KAAK,CAAC,YAAY,CAAC,OAAO;QACxB,OAAO,CACL,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;YAC1D,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,CAC3D,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAO;QACxB,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;QACxE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4B,CAAC;QAC9D,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;QACrE,MAAM,eAAe,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC/D,OAAO,QAAQ;aACZ,MAAM,CACL,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAClB,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC;YACpC,uBAAuB,CAAC,WAAW,CAAC;YACpC,uBAAuB,CAAC,eAAe,CAAC,CAC3C;aACA,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;YAC1C,IAAI;YACJ,SAAS;YACT,GAAG,EAAE,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC;gBACvC,CAAC,CAAC,YAAY,OAAO,CAAC,IAAI,EAAE;gBAC5B,CAAC,CAAC,aAAa,OAAO,CAAC,IAAI,EAAE;SAChC,CAAC,CAAC,CAAC;IACR,CAAC;IAED,oBAAoB,CAAC,OAAO,EAAE,QAAQ;QACpC,wDAAwD;QACxD,MAAM,oBAAoB,GACxB,OAAO,CAAC,QAAQ,KAAK,IAAI;YACvB,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,KAAK;gBAC1B,CAAC,CAAC,CAAC;gBACH,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;QACzB,OAAO;YACL,MAAM;YACN,aAAa;YACb,GAAG,CAAC,oBAAoB,IAAI,IAAI;gBAC9B,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,CAAC,2BAA2B,oBAAoB,EAAE,CAAC,CAAC;YACxD,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,YAAY,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC;YAC/D,OAAO,CAAC,IAAI;SACb,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACd,CAAC;CACF,CAAC"}
@@ -1,2 +1,2 @@
1
- import type { MonorepoToolHandler } from '../tools';
1
+ import type { MonorepoToolHandler } from '../tools.js';
2
2
  export declare const turboHandler: MonorepoToolHandler;
@@ -0,0 +1,48 @@
1
+ import path from 'node:path';
2
+ import { fileExists, readJsonFile } from '@code-pushup/utils';
3
+ import { npmHandler } from './npm.js';
4
+ import { pnpmHandler } from './pnpm.js';
5
+ import { yarnHandler } from './yarn.js';
6
+ const WORKSPACE_HANDLERS = [pnpmHandler, yarnHandler, npmHandler];
7
+ export const turboHandler = {
8
+ tool: 'turbo',
9
+ async isConfigured(options) {
10
+ const configPath = path.join(options.cwd, 'turbo.json');
11
+ return ((await fileExists(configPath)) &&
12
+ options.task in (await readJsonFile(configPath)).tasks);
13
+ },
14
+ async listProjects(options) {
15
+ // eslint-disable-next-line functional/no-loop-statements
16
+ for (const handler of WORKSPACE_HANDLERS) {
17
+ if (await handler.isConfigured(options)) {
18
+ const projects = await handler.listProjects(options);
19
+ return projects
20
+ .filter(({ bin }) => bin.includes(`run ${options.task}`)) // must have package.json script
21
+ .map(({ name, directory }) => ({
22
+ name,
23
+ directory,
24
+ bin: `npx turbo run ${options.task} --`,
25
+ }));
26
+ }
27
+ }
28
+ throw new Error(`Package manager with workspace configuration not found in Turborepo, expected one of ${WORKSPACE_HANDLERS.map(({ tool }) => tool).join('/')}`);
29
+ },
30
+ createRunManyCommand(options, projects) {
31
+ // https://turbo.build/repo/docs/reference/run#--concurrency-number--percentage
32
+ const concurrency = options.parallel === true
33
+ ? null
34
+ : options.parallel === false
35
+ ? 1
36
+ : options.parallel;
37
+ return [
38
+ 'npx',
39
+ 'turbo',
40
+ 'run',
41
+ options.task,
42
+ ...(projects.only?.map(project => `--filter=${project}`) ?? []),
43
+ ...(concurrency == null ? [] : [`--concurrency=${concurrency}`]),
44
+ '--',
45
+ ].join(' ');
46
+ },
47
+ };
48
+ //# sourceMappingURL=turbo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turbo.js","sourceRoot":"","sources":["../../../../../../../packages/ci/src/lib/monorepo/handlers/turbo.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,kBAAkB,GAAG,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;AAMlE,MAAM,CAAC,MAAM,YAAY,GAAwB;IAC/C,IAAI,EAAE,OAAO;IAEb,KAAK,CAAC,YAAY,CAAC,OAAO;QACxB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QACxD,OAAO,CACL,CAAC,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;YAC9B,OAAO,CAAC,IAAI,IAAI,CAAC,MAAM,YAAY,CAAc,UAAU,CAAC,CAAC,CAAC,KAAK,CACpE,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAO;QACxB,yDAAyD;QACzD,KAAK,MAAM,OAAO,IAAI,kBAAkB,EAAE,CAAC;YACzC,IAAI,MAAM,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;gBACxC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;gBACrD,OAAO,QAAQ;qBACZ,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,gCAAgC;qBACzF,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;oBAC7B,IAAI;oBACJ,SAAS;oBACT,GAAG,EAAE,iBAAiB,OAAO,CAAC,IAAI,KAAK;iBACxC,CAAC,CAAC,CAAC;YACR,CAAC;QACH,CAAC;QACD,MAAM,IAAI,KAAK,CACb,wFAAwF,kBAAkB,CAAC,GAAG,CAC5G,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CACnB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CACd,CAAC;IACJ,CAAC;IAED,oBAAoB,CAAC,OAAO,EAAE,QAAQ;QACpC,+EAA+E;QAC/E,MAAM,WAAW,GACf,OAAO,CAAC,QAAQ,KAAK,IAAI;YACvB,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,KAAK;gBAC1B,CAAC,CAAC,CAAC;gBACH,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;QACzB,OAAO;YACL,KAAK;YACL,OAAO;YACP,KAAK;YACL,OAAO,CAAC,IAAI;YACZ,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,YAAY,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC;YAC/D,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,iBAAiB,WAAW,EAAE,CAAC,CAAC;YAChE,IAAI;SACL,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACd,CAAC;CACF,CAAC"}
@@ -1,2 +1,2 @@
1
- import type { MonorepoToolHandler } from '../tools';
1
+ import type { MonorepoToolHandler } from '../tools.js';
2
2
  export declare const yarnHandler: MonorepoToolHandler;
@@ -0,0 +1,44 @@
1
+ import path from 'node:path';
2
+ import { executeProcess, fileExists } from '@code-pushup/utils';
3
+ import { hasCodePushUpDependency, hasScript, hasWorkspacesEnabled, listWorkspaces, } from '../packages.js';
4
+ export const yarnHandler = {
5
+ tool: 'yarn',
6
+ async isConfigured(options) {
7
+ return ((await fileExists(path.join(options.cwd, 'yarn.lock'))) &&
8
+ (await hasWorkspacesEnabled(options.cwd)));
9
+ },
10
+ async listProjects(options) {
11
+ const { workspaces, rootPackageJson } = await listWorkspaces(options.cwd);
12
+ return workspaces
13
+ .filter(({ packageJson }) => hasScript(packageJson, options.task) ||
14
+ hasCodePushUpDependency(packageJson) ||
15
+ hasCodePushUpDependency(rootPackageJson))
16
+ .map(({ name, directory, packageJson }) => ({
17
+ name,
18
+ directory,
19
+ bin: hasScript(packageJson, options.task)
20
+ ? `yarn run ${options.task}`
21
+ : `yarn exec ${options.task}`,
22
+ }));
23
+ },
24
+ async createRunManyCommand(options, projects) {
25
+ const { stdout } = await executeProcess({ command: 'yarn', args: ['-v'] });
26
+ const isV1 = stdout.startsWith('1.');
27
+ if (isV1) {
28
+ // neither parallel execution nor projects filter are supported in Yarn v1
29
+ return `yarn workspaces run ${options.task}`;
30
+ }
31
+ return [
32
+ 'yarn',
33
+ 'workspaces',
34
+ 'foreach',
35
+ ...(options.parallel ? ['--parallel'] : []),
36
+ ...(typeof options.parallel === 'number'
37
+ ? [`--jobs=${options.parallel}`]
38
+ : []),
39
+ ...(projects.only?.map(project => `--include=${project}`) ?? ['--all']),
40
+ options.task,
41
+ ].join(' ');
42
+ },
43
+ };
44
+ //# sourceMappingURL=yarn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yarn.js","sourceRoot":"","sources":["../../../../../../../packages/ci/src/lib/monorepo/handlers/yarn.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EACL,uBAAuB,EACvB,SAAS,EACT,oBAAoB,EACpB,cAAc,GACf,MAAM,gBAAgB,CAAC;AAGxB,MAAM,CAAC,MAAM,WAAW,GAAwB;IAC9C,IAAI,EAAE,MAAM;IAEZ,KAAK,CAAC,YAAY,CAAC,OAAO;QACxB,OAAO,CACL,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;YACvD,CAAC,MAAM,oBAAoB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAC1C,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAO;QACxB,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC1E,OAAO,UAAU;aACd,MAAM,CACL,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAClB,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC;YACpC,uBAAuB,CAAC,WAAW,CAAC;YACpC,uBAAuB,CAAC,eAAe,CAAC,CAC3C;aACA,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;YAC1C,IAAI;YACJ,SAAS;YACT,GAAG,EAAE,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC;gBACvC,CAAC,CAAC,YAAY,OAAO,CAAC,IAAI,EAAE;gBAC5B,CAAC,CAAC,aAAa,OAAO,CAAC,IAAI,EAAE;SAChC,CAAC,CAAC,CAAC;IACR,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,OAAO,EAAE,QAAQ;QAC1C,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,cAAc,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3E,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAErC,IAAI,IAAI,EAAE,CAAC;YACT,0EAA0E;YAC1E,OAAO,uBAAuB,OAAO,CAAC,IAAI,EAAE,CAAC;QAC/C,CAAC;QAED,OAAO;YACL,MAAM;YACN,YAAY;YACZ,SAAS;YACT,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3C,GAAG,CAAC,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ;gBACtC,CAAC,CAAC,CAAC,UAAU,OAAO,CAAC,QAAQ,EAAE,CAAC;gBAChC,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,aAAa,OAAO,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvE,OAAO,CAAC,IAAI;SACb,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACd,CAAC;CACF,CAAC"}
@@ -1,2 +1,2 @@
1
- export { listMonorepoProjects } from './list-projects';
2
- export { MONOREPO_TOOLS, isMonorepoTool, type MonorepoTool, type ProjectConfig, } from './tools';
1
+ export { listMonorepoProjects, type RunManyCommand } from './list-projects.js';
2
+ export { isMonorepoTool, MONOREPO_TOOLS, type MonorepoTool, type ProjectConfig, } from './tools.js';
@@ -0,0 +1,3 @@
1
+ export { listMonorepoProjects } from './list-projects.js';
2
+ export { isMonorepoTool, MONOREPO_TOOLS, } from './tools.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/ci/src/lib/monorepo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAuB,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EACL,cAAc,EACd,cAAc,GAGf,MAAM,YAAY,CAAC"}
@@ -1,3 +1,9 @@
1
- import type { Settings } from '../models';
2
- import type { ProjectConfig } from './tools';
3
- export declare function listMonorepoProjects(settings: Settings): Promise<ProjectConfig[]>;
1
+ import type { Settings } from '../models.js';
2
+ import type { MonorepoTool, ProjectConfig } from './tools.js';
3
+ export type MonorepoProjects = {
4
+ tool: MonorepoTool | null;
5
+ projects: ProjectConfig[];
6
+ runManyCommand?: RunManyCommand;
7
+ };
8
+ export type RunManyCommand = (onlyProjects?: string[]) => string | Promise<string>;
9
+ export declare function listMonorepoProjects(settings: Settings): Promise<MonorepoProjects>;
@@ -0,0 +1,99 @@
1
+ import { glob } from 'glob';
2
+ import path from 'node:path';
3
+ import { detectMonorepoTool } from './detect-tool.js';
4
+ import { getToolHandler } from './handlers/index.js';
5
+ import { listPackages } from './packages.js';
6
+ export async function listMonorepoProjects(settings) {
7
+ const logger = settings.logger;
8
+ const options = createMonorepoHandlerOptions(settings);
9
+ const tool = await resolveMonorepoTool(settings, options);
10
+ if (tool) {
11
+ const handler = getToolHandler(tool);
12
+ const projects = await handler.listProjects(options);
13
+ logger.info(`Found ${projects.length} projects in ${tool} monorepo`);
14
+ logger.debug(`Projects: ${projects.map(({ name }) => name).join(', ')}`);
15
+ return {
16
+ tool,
17
+ projects,
18
+ runManyCommand: onlyProjects => handler.createRunManyCommand(options, {
19
+ all: projects,
20
+ ...(onlyProjects?.length && { only: onlyProjects }),
21
+ }),
22
+ };
23
+ }
24
+ if (settings.projects) {
25
+ const projects = await listProjectsByGlobs({
26
+ patterns: settings.projects,
27
+ cwd: options.cwd,
28
+ bin: settings.bin,
29
+ logger,
30
+ });
31
+ return { tool, projects };
32
+ }
33
+ const projects = await listProjectsByNpmPackages({
34
+ cwd: options.cwd,
35
+ bin: settings.bin,
36
+ logger,
37
+ });
38
+ return { tool, projects };
39
+ }
40
+ async function resolveMonorepoTool(settings, options) {
41
+ if (!settings.monorepo) {
42
+ // shouldn't happen, handled by caller
43
+ throw new Error('Monorepo mode not enabled');
44
+ }
45
+ const logger = settings.logger;
46
+ if (typeof settings.monorepo === 'string') {
47
+ logger.info(`Using monorepo tool "${settings.monorepo}" from inputs`);
48
+ return settings.monorepo;
49
+ }
50
+ const tool = await detectMonorepoTool(options);
51
+ if (tool) {
52
+ logger.info(`Auto-detected monorepo tool ${tool}`);
53
+ }
54
+ else {
55
+ logger.info("Couldn't auto-detect any supported monorepo tool");
56
+ }
57
+ return tool;
58
+ }
59
+ function createMonorepoHandlerOptions(settings) {
60
+ return {
61
+ task: settings.task,
62
+ cwd: settings.directory,
63
+ parallel: settings.parallel,
64
+ nxProjectsFilter: settings.nxProjectsFilter,
65
+ ...(!settings.silent && {
66
+ observer: {
67
+ onStdout: stdout => {
68
+ console.info(stdout);
69
+ },
70
+ onStderr: stderr => {
71
+ console.warn(stderr);
72
+ },
73
+ },
74
+ }),
75
+ };
76
+ }
77
+ async function listProjectsByGlobs(args) {
78
+ const { patterns, cwd, bin, logger } = args;
79
+ const directories = await glob(patterns.map(pattern => pattern.replace(/\/$/, '/')), { cwd });
80
+ logger.info(`Found ${directories.length} project folders matching "${patterns.join(', ')}" from configuration`);
81
+ logger.debug(`Projects: ${directories.join(', ')}`);
82
+ return directories.toSorted().map(directory => ({
83
+ name: directory,
84
+ bin,
85
+ directory: path.join(cwd, directory),
86
+ }));
87
+ }
88
+ async function listProjectsByNpmPackages(args) {
89
+ const { cwd, bin, logger } = args;
90
+ const packages = await listPackages(cwd);
91
+ logger.info(`Found ${packages.length} NPM packages in repository`);
92
+ logger.debug(`Projects: ${packages.map(({ name }) => name).join(', ')}`);
93
+ return packages.map(({ name, directory }) => ({
94
+ name,
95
+ bin,
96
+ directory,
97
+ }));
98
+ }
99
+ //# sourceMappingURL=list-projects.js.map