diff --git a/.changeset/big-months-deliver.md b/.changeset/big-months-deliver.md new file mode 100644 index 0000000000..1cf873beb1 --- /dev/null +++ b/.changeset/big-months-deliver.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Added `--since ` flag for `repo build` command.` diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index d3baa37b3f..5cb02c82b4 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -41,6 +41,10 @@ export function registerRepoCommand(program: CommanderStatic) { '--all', 'Build all packages, including bundled app and backend packages.', ) + .option( + '--since ', + 'Only build packages and their dev dependents that changed since the specified ref', + ) .action(lazy(() => import('./repo/build').then(m => m.command))); command diff --git a/packages/cli/src/commands/repo/build.ts b/packages/cli/src/commands/repo/build.ts index ceb468ebfa..fe50bee84f 100644 --- a/packages/cli/src/commands/repo/build.ts +++ b/packages/cli/src/commands/repo/build.ts @@ -78,7 +78,18 @@ function createScriptOptionsParser(anyCmd: Command, commandPath: string[]) { } export async function command(cmd: Command): Promise { - const packages = await PackageGraph.listTargetPackages(); + let packages = await PackageGraph.listTargetPackages(); + + if (cmd.since) { + const graph = PackageGraph.fromPackages(packages); + const changedPackages = await graph.listChangedPackages({ ref: cmd.since }); + const withDevDependents = graph.collectPackageNames( + changedPackages.map(pkg => pkg.name), + pkg => pkg.localDevDependents.keys(), + ); + packages = Array.from(withDevDependents).map(name => graph.get(name)!); + } + const apps = new Array(); const backends = new Array(); diff --git a/packages/cli/src/lib/monorepo/PackageGraph.test.ts b/packages/cli/src/lib/monorepo/PackageGraph.test.ts index 06427a7313..feb1709bf7 100644 --- a/packages/cli/src/lib/monorepo/PackageGraph.test.ts +++ b/packages/cli/src/lib/monorepo/PackageGraph.test.ts @@ -87,6 +87,11 @@ describe('PackageGraph', () => { localDependencies: new Map([['b', b]]), localDevDependencies: new Map([['c', c]]), localOptionalDependencies: new Map(), + allLocalDependents: new Map(), + publishedLocalDependents: new Map(), + localDependents: new Map(), + localDevDependents: new Map(), + localOptionalDependents: new Map(), }); expect(b).toMatchObject({ name: 'b', @@ -96,6 +101,11 @@ describe('PackageGraph', () => { localDependencies: new Map(), localDevDependencies: new Map([['c', c]]), localOptionalDependencies: new Map(), + allLocalDependents: new Map([['a', a]]), + publishedLocalDependents: new Map([['a', a]]), + localDependents: new Map([['a', a]]), + localDevDependents: new Map(), + localOptionalDependents: new Map(), }); expect(c).toMatchObject({ name: 'c', @@ -105,6 +115,17 @@ describe('PackageGraph', () => { localDependencies: new Map(), localDevDependencies: new Map(), localOptionalDependencies: new Map(), + allLocalDependents: new Map([ + ['a', a], + ['b', b], + ]), + publishedLocalDependents: new Map(), + localDependents: new Map(), + localDevDependents: new Map([ + ['a', a], + ['b', b], + ]), + localOptionalDependents: new Map(), }); }); diff --git a/packages/cli/src/lib/monorepo/PackageGraph.ts b/packages/cli/src/lib/monorepo/PackageGraph.ts index 4bbb9eac67..c65f5c003c 100644 --- a/packages/cli/src/lib/monorepo/PackageGraph.ts +++ b/packages/cli/src/lib/monorepo/PackageGraph.ts @@ -47,6 +47,7 @@ export type PackageGraphNode = { dir: string; /** The package data of the package itself */ packageJson: ExtendedPackageJSON; + /** All direct local dependencies of the package */ allLocalDependencies: Map; /** All direct local dependencies that will be present in the published package */ @@ -57,6 +58,17 @@ export type PackageGraphNode = { localDevDependencies: Map; /** Local optionalDependencies */ localOptionalDependencies: Map; + + /** All direct incoming local dependencies of the package */ + allLocalDependents: Map; + /** All direct incoming local dependencies that will be present in the published package */ + publishedLocalDependents: Map; + /** Incoming local dependencies */ + localDependents: Map; + /** Incoming local devDependencies */ + localDevDependents: Map; + /** Incoming local optionalDependencies */ + localOptionalDependents: Map; }; export class PackageGraph extends Map { @@ -82,11 +94,18 @@ export class PackageGraph extends Map { name, dir: pkg.dir, packageJson: pkg.packageJson as ExtendedPackageJSON, + allLocalDependencies: new Map(), publishedLocalDependencies: new Map(), localDependencies: new Map(), localDevDependencies: new Map(), localOptionalDependencies: new Map(), + + allLocalDependents: new Map(), + publishedLocalDependents: new Map(), + localDependents: new Map(), + localDevDependents: new Map(), + localOptionalDependents: new Map(), }); } @@ -98,6 +117,10 @@ export class PackageGraph extends Map { node.allLocalDependencies.set(depName, depPkg); node.publishedLocalDependencies.set(depName, depPkg); node.localDependencies.set(depName, depPkg); + + depPkg.allLocalDependents.set(node.name, node); + depPkg.publishedLocalDependents.set(node.name, node); + depPkg.localDependents.set(node.name, node); } } for (const depName of Object.keys( @@ -107,6 +130,9 @@ export class PackageGraph extends Map { if (depPkg) { node.allLocalDependencies.set(depName, depPkg); node.localDevDependencies.set(depName, depPkg); + + depPkg.allLocalDependents.set(node.name, node); + depPkg.localDevDependents.set(node.name, node); } } for (const depName of Object.keys( @@ -117,6 +143,10 @@ export class PackageGraph extends Map { node.allLocalDependencies.set(depName, depPkg); node.publishedLocalDependencies.set(depName, depPkg); node.localOptionalDependencies.set(depName, depPkg); + + depPkg.allLocalDependents.set(node.name, node); + depPkg.publishedLocalDependents.set(node.name, node); + depPkg.localOptionalDependents.set(node.name, node); } } }