diff --git a/libs/core/README.md b/libs/core/README.md index 21e948d..44e2981 100644 --- a/libs/core/README.md +++ b/libs/core/README.md @@ -40,13 +40,13 @@ const affected = await trueAffected({ ### **Options** -| Option | Type | Description | Default | -| -------------- | ----------- | ------------------------------------------------------------ | ------------- | -| `rootTsConfig` | `string` | The path to the root tsconfig file | | -| `projects` | `Project[]` | An array of projects to check | | -| `cwd` | `string` | The current working directory | | -| `base` | `string` | The base branch to compare against | `origin/main` | -| `includeFiles` | `string[]` | Glob patterns to include (relative to projects' source root) | | +| Option | Type | Description | Default | +| -------------- | ----------------------- | ------------------------------------------------------------ | ----------------- | +| `rootTsConfig` | `string` | The path to the root tsconfig file | | +| `projects` | `Project[]` | An array of projects to check | | +| `cwd` | `string` | The current working directory | | +| `base` | `string` | The base branch to compare against | `origin/main` | +| `include` | `(string \| Regexp)[]` | Glob patterns to include (relative to projects' source root) | spec & test files | > `rootTsConfig` - The path to the root tsconfig file, should include the `paths` prop with all projects mapping so `ts-morph` can find the references. diff --git a/libs/core/src/true-affected.spec.ts b/libs/core/src/true-affected.spec.ts index e7ef2fa..8ec89a6 100644 --- a/libs/core/src/true-affected.spec.ts +++ b/libs/core/src/true-affected.spec.ts @@ -165,77 +165,6 @@ describe('trueAffected', () => { expect(affected).toEqual(['proj1', 'proj3']); }); - it('should include test files by suffixes', async () => { - jest.spyOn(git, 'getChangedFiles').mockReturnValue([ - { - filePath: 'proj1/index._test_.ts', - changedLines: [6], - }, - ]); - - const affected = await trueAffected({ - cwd, - base: 'main', - rootTsConfig: 'tsconfig.json', - projects: [ - { - name: 'proj1', - sourceRoot: 'proj1/', - tsConfig: 'proj1/tsconfig.json', - }, - { - name: 'proj2', - sourceRoot: 'proj2/', - tsConfig: 'proj2/tsconfig.json', - }, - { - name: 'proj3', - sourceRoot: 'proj3/', - tsConfig: 'proj3/tsconfig.json', - implicitDependencies: ['proj1'], - }, - ], - testSuffixes: ['_test_'], - }); - - expect(affected).toEqual(['proj1', 'proj3']); - }); - - it('should default test files suffixes to spec and test', async () => { - jest.spyOn(git, 'getChangedFiles').mockReturnValue([ - { - filePath: 'proj1/index.spec.ts', - changedLines: [6], - }, - ]); - - const affected = await trueAffected({ - cwd, - base: 'main', - rootTsConfig: 'tsconfig.json', - projects: [ - { - name: 'proj1', - sourceRoot: 'proj1/', - tsConfig: 'proj1/tsconfig.json', - }, - { - name: 'proj2', - sourceRoot: 'proj2/', - tsConfig: 'proj2/tsconfig.json', - }, - { - name: 'proj3', - sourceRoot: 'proj3/', - tsConfig: 'proj3/tsconfig.json', - implicitDependencies: ['proj1'], - }, - ], - }); - - expect(affected).toEqual(['proj1', 'proj3']); - }); - it('should ignore files that are not in projects files', async () => { jest.spyOn(git, 'getChangedFiles').mockReturnValue([ { @@ -381,16 +310,12 @@ describe('trueAffected', () => { it.each([ ['regular path', ['package.json'], ['proj3']], - ['glob path', ['**/package.json'], ['proj3']], - [ - 'multiple paths', - ['package.json', '**/jest.config.js'], - ['proj2', 'proj3'], - ], + ['regexp path', [/\.spec\.ts$/], ['proj1']], + ['multiple paths', ['package.json', /\.spec\.ts$/], ['proj1', 'proj3']], ])('should include files with %s', async (title, filePatterns, expected) => { jest.spyOn(git, 'getChangedFiles').mockReturnValue([ { - filePath: 'proj2/jest.config.js', + filePath: 'proj1/test.spec.ts', changedLines: [1], }, { @@ -420,7 +345,7 @@ describe('trueAffected', () => { tsConfig: 'proj3/tsconfig.json', }, ], - includeFiles: filePatterns, + include: filePatterns, }); expect(affected).toEqual(expected); diff --git a/libs/core/src/true-affected.ts b/libs/core/src/true-affected.ts index 149fcb1..21367cb 100644 --- a/libs/core/src/true-affected.ts +++ b/libs/core/src/true-affected.ts @@ -17,13 +17,14 @@ const ignoredRootNodeTypes = [ SyntaxKind.IfStatement, ]; +export const DEFAULT_INCLUDE_TEST_FILES = /\.(spec|test)\.(ts|js)x?/; + export const trueAffected = async ({ cwd, rootTsConfig, base = 'origin/main', projects, - includeFiles = [], - testSuffixes = ['spec', 'test'], + include = [DEFAULT_INCLUDE_TEST_FILES], }: TrueAffected) => { const project = new Project({ compilerOptions: { @@ -58,26 +59,21 @@ export const trueAffected = async ({ join(resolve(cwd, sourceRoot), '**/*.{ts,js}') ); } - - project.addSourceFilesAtPaths( - includeFiles.map((path) => `${resolve(cwd, sourceRoot)}/${path}`) - ); } ); - const sourceChangedFiles: GetChangedFiles[] = getChangedFiles({ + const changedFiles = getChangedFiles({ base, cwd, - }).filter( + }); + + const sourceChangedFiles: GetChangedFiles[] = changedFiles.filter( ({ filePath }) => project.getSourceFile(resolve(cwd, filePath)) != null ); const ignoredPaths = ['./node_modules', './dist', './.git']; - const nonSourceChangedFiles: GetChangedFiles[] = getChangedFiles({ - base, - cwd, - }) + const nonSourceChangedFiles: GetChangedFiles[] = changedFiles .filter( ({ filePath }) => !filePath.match(/.*\.(ts|js)x?$/g) && @@ -87,16 +83,23 @@ export const trueAffected = async ({ findNonSourceAffectedFiles(cwd, changedFilePath, ignoredPaths) ); - const changedFiles = [...sourceChangedFiles, ...nonSourceChangedFiles]; + const filteredChangedFiles = [ + ...sourceChangedFiles, + ...nonSourceChangedFiles, + ]; - const changedTestFilesPackages = changedFiles + const changedIncludedFilesPackages = changedFiles .filter(({ filePath }) => - new RegExp(`.*\\.(${testSuffixes.join('|')})\\.(ts|js)x?$`).test(filePath) + include.some((file) => + typeof file === 'string' + ? filePath.endsWith(file) + : filePath.match(file) + ) ) .map(({ filePath }) => getPackageNameByPath(filePath, projects)) .filter((v): v is string => v != null); - const affectedPackages = new Set(changedTestFilesPackages); + const affectedPackages = new Set(changedIncludedFilesPackages); const visitedIdentifiers = new Map(); const findReferencesLibs = (node: Node) => { @@ -134,7 +137,7 @@ export const trueAffected = async ({ }); }; - changedFiles.forEach(({ filePath, changedLines }) => { + filteredChangedFiles.forEach(({ filePath, changedLines }) => { const sourceFile = project.getSourceFile(resolve(cwd, filePath)); if (sourceFile == null) return; diff --git a/libs/core/src/types.ts b/libs/core/src/types.ts index 65ef87f..704133b 100644 --- a/libs/core/src/types.ts +++ b/libs/core/src/types.ts @@ -11,6 +11,5 @@ export interface TrueAffected { rootTsConfig?: string; base?: string; projects: TrueAffectedProject[]; - includeFiles?: string[]; - testSuffixes?: string[]; + include?: (string | RegExp)[]; } diff --git a/libs/nx/src/cli.spec.ts b/libs/nx/src/cli.spec.ts index 4ecba20..88dbd2d 100644 --- a/libs/nx/src/cli.spec.ts +++ b/libs/nx/src/cli.spec.ts @@ -136,7 +136,7 @@ describe('cli', () => { rootTsConfig: 'tsconfig.base.json', base: 'origin/main', projects: [], - includeFiles: [], + include: [], }); }); diff --git a/libs/nx/src/cli.ts b/libs/nx/src/cli.ts index 039ce9e..5a43820 100644 --- a/libs/nx/src/cli.ts +++ b/libs/nx/src/cli.ts @@ -4,7 +4,7 @@ import { spawn } from 'node:child_process'; import { CommandModule } from 'yargs'; import { hideBin } from 'yargs/helpers'; import yargs from 'yargs/yargs'; -import { trueAffected } from '@traf/core'; +import { DEFAULT_INCLUDE_TEST_FILES, trueAffected } from '@traf/core'; import { getNxTrueAffectedProjects } from './nx'; const color = '#ff0083'; @@ -43,7 +43,7 @@ export const affectedAction = async ({ rootTsConfig: tsConfigFilePath, base, projects, - includeFiles, + include: [...includeFiles, DEFAULT_INCLUDE_TEST_FILES], }); if (json) {