diff --git a/libs/core/src/types.ts b/libs/core/src/types.ts index f88cdb4..fd9c938 100644 --- a/libs/core/src/types.ts +++ b/libs/core/src/types.ts @@ -3,6 +3,7 @@ export interface TrueAffectedProject { sourceRoot: string; tsConfig?: string; implicitDependencies?: string[]; + targets?: string[]; } export interface TrueAffected { diff --git a/libs/nx/README.md b/libs/nx/README.md index 67515db..47726b6 100644 --- a/libs/nx/README.md +++ b/libs/nx/README.md @@ -17,7 +17,7 @@ npx @traf/nx@latest affected [options] ### **Options** | Option | Description | Default | -| -------------------- | ------------------------------------------------------------------------------------ | -------------------- | +|----------------------|--------------------------------------------------------------------------------------| -------------------- | | `--cwd` | The current working directory | `process.cwd()` | | `--all` | Outputs all available projects regardless of changes | `false` | | `--base` | The base branch to compare against | `origin/main` | @@ -25,3 +25,4 @@ npx @traf/nx@latest affected [options] | `--action` | The action to perform. Can be any command | `log` | | `--json` | Output the result as JSON | `false` | | `--includeFiles` | Comma separated list of glob patterns to include (relative to projects' source root) | | +| `--target` | Comma separated list of targets to filter affected projects by | | diff --git a/libs/nx/src/cli.spec.ts b/libs/nx/src/cli.spec.ts index 1db5aa5..4ecba20 100644 --- a/libs/nx/src/cli.spec.ts +++ b/libs/nx/src/cli.spec.ts @@ -71,6 +71,7 @@ describe('cli', () => { json: false, restArgs: [], tsConfigFilePath: 'tsconfig.base.json', + target: [], }); }); @@ -93,6 +94,7 @@ describe('cli', () => { json: false, restArgs: [], tsConfigFilePath: 'tsconfig.json', + target: [], }); }); }); @@ -125,6 +127,7 @@ describe('cli', () => { json: false, restArgs: [], tsConfigFilePath: 'tsconfig.base.json', + target: [], }); expect(getNxTrueAffectedProjectsSpy).toBeCalledWith(process.cwd()); @@ -150,6 +153,7 @@ describe('cli', () => { json: false, restArgs: [], tsConfigFilePath: 'tsconfig.base.json', + target: [], }); expect(logSpy).toHaveBeenCalledWith('No affected projects'); @@ -167,6 +171,7 @@ describe('cli', () => { json: false, restArgs: [], tsConfigFilePath: 'tsconfig.base.json', + target: [], }); expect(logSpy).toHaveBeenCalledWith('Affected projects:\n - proj1'); @@ -186,6 +191,7 @@ describe('cli', () => { json: true, restArgs: [], tsConfigFilePath: 'tsconfig.base.json', + target: [], }); expect(consoleSpy).toHaveBeenCalledWith('["proj1"]'); @@ -206,6 +212,7 @@ describe('cli', () => { json: false, restArgs: [], tsConfigFilePath: 'tsconfig.base.json', + target: [], }); const expectedCommand = `npx nx run-many --target=build --projects=proj1 `; @@ -219,13 +226,50 @@ describe('cli', () => { ); }); + describe('`target` option', () => { + beforeEach(() => { + trafSpy.mockResolvedValueOnce(['proj1']); + + getNxTrueAffectedProjectsSpy.mockResolvedValueOnce([ + { + name: 'proj1', + sourceRoot: 'mock', + tsConfig: 'mock', + targets: ['build'], + }, + { + name: 'proj2', + sourceRoot: 'mock', + tsConfig: 'mock', + targets: ['test'], + }, + ]); + }); + + it('should only return projects with a build target', async () => { + await cli.affectedAction({ + action: 'log', + all: false, + base: 'origin/main', + cwd: process.cwd(), + includeFiles: [], + json: false, + restArgs: [], + tsConfigFilePath: 'tsconfig.base.json', + target: ['build'], + }); + + expect(logSpy).toHaveBeenCalledWith('Affected projects:\n - proj1'); + }); + }); + describe('`all` option', () => { beforeEach(() => { trafSpy.mockResolvedValueOnce(['proj1']); getNxTrueAffectedProjectsSpy.mockResolvedValueOnce([ - { name: 'proj1', sourceRoot: 'mock', tsConfig: 'mock' }, - { name: 'proj2', sourceRoot: 'mock', tsConfig: 'mock' }, + { name: 'proj1', sourceRoot: 'mock', tsConfig: 'mock', targets: [] }, + { name: 'proj2', sourceRoot: 'mock', tsConfig: 'mock', targets: [] }, ]); }); @@ -239,6 +283,7 @@ describe('cli', () => { json: false, restArgs: [], tsConfigFilePath: 'tsconfig.base.json', + target: [], }); expect(logSpy).toHaveBeenCalledWith('Affected projects:\n - proj1'); @@ -254,6 +299,7 @@ describe('cli', () => { json: false, restArgs: [], tsConfigFilePath: 'tsconfig.base.json', + target: [], }); expect(logSpy).toHaveBeenCalledWith( diff --git a/libs/nx/src/cli.ts b/libs/nx/src/cli.ts index c394213..039ce9e 100644 --- a/libs/nx/src/cli.ts +++ b/libs/nx/src/cli.ts @@ -23,8 +23,18 @@ export const affectedAction = async ({ restArgs, tsConfigFilePath, includeFiles, + target, }: AffectedOptions) => { - const projects = await getNxTrueAffectedProjects(cwd); + let projects = await getNxTrueAffectedProjects(cwd); + + if (target.length) { + projects = projects.filter( + (project) => + !!project.targets?.some((projectTarget) => + target.includes(projectTarget) + ) + ); + } const affected = all ? projects.map((p) => p.name) @@ -80,6 +90,7 @@ interface AffectedOptions { json: boolean; includeFiles: string[]; restArgs: string[]; + target: string[]; } const affectedCommand: CommandModule = { @@ -119,6 +130,14 @@ const affectedCommand: CommandModule = { return array.flatMap((v) => v.split(',')); }, }, + target: { + desc: 'Comma separate list of targets to filter affected projects by', + type: 'array', + default: [], + coerce: (array: string[]) => { + return array.flatMap((v) => v.split(',')).map((v) => v.trim()); + }, + }, }, handler: async ({ cwd, @@ -128,6 +147,7 @@ const affectedCommand: CommandModule = { base, json, includeFiles, + target, // eslint-disable-next-line @typescript-eslint/no-unused-vars $0, // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -142,6 +162,7 @@ const affectedCommand: CommandModule = { base, json, includeFiles, + target, restArgs: Object.entries(rest).map( /* istanbul ignore next */ ([key, value]) => `--${key}=${value}` diff --git a/libs/nx/src/nx.ts b/libs/nx/src/nx.ts index 6cffad3..94095b7 100644 --- a/libs/nx/src/nx.ts +++ b/libs/nx/src/nx.ts @@ -124,6 +124,7 @@ export async function getNxTrueAffectedProjects( sourceRoot: project.sourceRoot, implicitDependencies: project.implicitDependencies ?? [], tsConfig, + targets: Object.keys(project.targets ?? {}), }; }); } diff --git a/tsconfig.base.json b/tsconfig.base.json index 023f0f4..7b786af 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -17,7 +17,7 @@ "paths": { "@traf/core": ["libs/core/src/index.ts"], "@traf/nx": ["libs/nx/src/cli.ts"], - "@traf/turbo": ["libs/turbo/src/cli.ts"], + "@traf/turbo": ["libs/turbo/src/cli.ts"] } }, "exclude": ["node_modules", "tmp"]