diff --git a/packages/gradle/plugin.spec.ts b/packages/gradle/plugin.spec.ts index 78dc8efe8b..4d9108e34f 100644 --- a/packages/gradle/plugin.spec.ts +++ b/packages/gradle/plugin.spec.ts @@ -23,7 +23,7 @@ describe('@nx/gradle/plugin', () => { gradleFileToGradleProjectMap: new Map([ ['proj/build.gradle', 'proj'], ]), - buildFileToDepsMap: new Map(), + buildFileToDepsMap: new Map>(), gradleFileToOutputDirsMap: new Map>([ ['proj/build.gradle', new Map([['build', 'build']])], ]), diff --git a/packages/gradle/src/plugin/dependencies.spec.ts b/packages/gradle/src/plugin/dependencies.spec.ts deleted file mode 100644 index 6b79e46163..0000000000 --- a/packages/gradle/src/plugin/dependencies.spec.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { join } from 'path'; -import { processGradleDependencies } from './dependencies'; - -jest.mock('@nx/devkit', () => ({ - ...jest.requireActual('@nx/devkit'), - validateDependency: jest.fn().mockReturnValue(true), -})); - -describe('processGradleDependencies', () => { - it('should process gradle dependencies with composite build', () => { - const depFilePath = join( - __dirname, - '..', - 'utils/__mocks__/gradle-composite-dependencies.txt' - ); - const dependencies = new Set([]); - processGradleDependencies( - depFilePath, - new Map([ - [':my-utils:number-utils', 'utilities/number-utils'], - [':my-utils:string-utils', 'utilities/string-utils'], - ]), - 'app', - 'app', - { - projects: { - 'number-utils': { - root: 'utilities/number-utils', - name: 'number-utils', - }, - 'string-utils': { - root: 'utilities/string-utils', - name: 'string-utils', - }, - utilities: { - root: 'utilities', - name: 'utilities', - }, - }, - } as any, - dependencies - ); - expect(Array.from(dependencies)).toEqual([ - { - source: 'app', - sourceFile: 'app', - target: 'number-utils', - type: 'static', - }, - { - source: 'app', - sourceFile: 'app', - target: 'string-utils', - type: 'static', - }, - ]); - }); - - it('should process gradle dependencies with regular build', () => { - const depFilePath = join( - __dirname, - '..', - 'utils/__mocks__/gradle-dependencies.txt' - ); - const dependencies = new Set([]); - processGradleDependencies( - depFilePath, - new Map([ - [':my-utils:number-utils', 'utilities/number-utils'], - [':my-utils:string-utils', 'utilities/string-utils'], - [':utilities', 'utilities'], - ]), - 'app', - 'app', - { - projects: { - 'number-utils': { - root: 'utilities/number-utils', - name: 'number-utils', - }, - 'string-utils': { - root: 'utilities/string-utils', - name: 'string-utils', - }, - utilities: { - root: 'utilities', - name: 'utilities', - }, - }, - } as any, - dependencies - ); - expect(Array.from(dependencies)).toEqual([ - { - source: 'app', - sourceFile: 'app', - target: 'utilities', - type: 'static', - }, - ]); - }); -}); diff --git a/packages/gradle/src/plugin/dependencies.ts b/packages/gradle/src/plugin/dependencies.ts index d306713064..67fc4006e9 100644 --- a/packages/gradle/src/plugin/dependencies.ts +++ b/packages/gradle/src/plugin/dependencies.ts @@ -6,12 +6,10 @@ import { RawProjectGraphDependency, validateDependency, } from '@nx/devkit'; -import { readFileSync } from 'node:fs'; import { basename, dirname } from 'node:path'; import { getCurrentGradleReport } from '../utils/get-gradle-report'; import { GRADLE_BUILD_FILES } from '../utils/split-config-files'; -import { newLineSeparator } from '../utils/get-project-report-lines'; export const createDependencies: CreateDependencies = async ( _, @@ -36,17 +34,25 @@ export const createDependencies: CreateDependencies = async ( const projectName = Object.values(context.projects).find( (project) => project.root === dirname(gradleFile) )?.name; - const depsFile = buildFileToDepsMap.get(gradleFile); + const dependedProjects: Set = buildFileToDepsMap.get(gradleFile); - if (projectName && depsFile) { - processGradleDependencies( - depsFile, - gradleProjectNameToProjectRootMap, - projectName, - gradleFile, - context, - dependencies - ); + if (projectName && dependedProjects?.size) { + dependedProjects?.forEach((dependedProject) => { + const targetProjectRoot = gradleProjectNameToProjectRootMap.get( + dependedProject + ) as string; + const targetProjectName = Object.values(context.projects).find( + (project) => project.root === targetProjectRoot + )?.name; + const dependency: RawProjectGraphDependency = { + source: projectName as string, + target: targetProjectName as string, + type: DependencyType.static, + sourceFile: gradleFile, + }; + validateDependency(dependency, context); + dependencies.add(dependency); + }); } gradleProjectToChildProjects.get(gradleProject)?.forEach((childProject) => { if (childProject) { @@ -85,60 +91,3 @@ function findGradleFiles(fileMap: FileMap): string[] { return gradleFiles; } - -export function processGradleDependencies( - depsFile: string, - gradleProjectNameToProjectRoot: Map, - sourceProjectName: string, - gradleFile: string, - context: CreateDependenciesContext, - dependencies: Set -): void { - const lines = readFileSync(depsFile).toString().split(newLineSeparator); - let inDeps = false; - for (const line of lines) { - if ( - line.startsWith('implementationDependenciesMetadata') || - line.startsWith('compileClasspath') - ) { - inDeps = true; - continue; - } - - if (inDeps) { - if (line === '') { - inDeps = false; - continue; - } - const [indents, dep] = line.split('--- '); - if (indents === '\\' || indents === '+') { - let gradleProjectName: string | undefined; - if (dep.startsWith('project ')) { - gradleProjectName = dep - .substring('project '.length) - .replace(/ \(n\)$/, '') - .trim(); - } else if (dep.includes('-> project')) { - const [_, projectName] = dep.split('-> project'); - gradleProjectName = projectName.trim(); - } - const targetProjectRoot = gradleProjectNameToProjectRoot.get( - gradleProjectName - ) as string; - const targetProjectName = Object.values(context.projects).find( - (project) => project.root === targetProjectRoot - )?.name; - if (targetProjectName) { - const dependency: RawProjectGraphDependency = { - source: sourceProjectName, - target: targetProjectName, - type: DependencyType.static, - sourceFile: gradleFile, - }; - validateDependency(dependency, context); - dependencies.add(dependency); - } - } - } - } -} diff --git a/packages/gradle/src/plugin/nodes.spec.ts b/packages/gradle/src/plugin/nodes.spec.ts index 2860777af9..c6dd65f87f 100644 --- a/packages/gradle/src/plugin/nodes.spec.ts +++ b/packages/gradle/src/plugin/nodes.spec.ts @@ -26,7 +26,7 @@ describe('@nx/gradle/plugin', () => { gradleFileToGradleProjectMap: new Map([ ['proj/build.gradle', 'proj'], ]), - buildFileToDepsMap: new Map(), + buildFileToDepsMap: new Map>(), gradleFileToOutputDirsMap: new Map>([ ['proj/build.gradle', new Map([['build', 'build']])], ]), @@ -249,7 +249,7 @@ describe('@nx/gradle/plugin', () => { gradleFileToGradleProjectMap: new Map([ ['nested/nested/proj/build.gradle', 'proj'], ]), - buildFileToDepsMap: new Map(), + buildFileToDepsMap: new Map>(), gradleFileToOutputDirsMap: new Map>([ ['nested/nested/proj/build.gradle', new Map([['build', 'build']])], ]), @@ -341,7 +341,7 @@ describe('@nx/gradle/plugin', () => { gradleFileToGradleProjectMap: new Map([ ['nested/nested/proj/build.gradle', 'proj'], ]), - buildFileToDepsMap: new Map(), + buildFileToDepsMap: new Map>(), gradleFileToOutputDirsMap: new Map>([ ['nested/nested/proj/build.gradle', new Map([['build', 'build']])], ]), diff --git a/packages/gradle/src/utils/get-gradle-report.spec.ts b/packages/gradle/src/utils/get-gradle-report.spec.ts index 014e3cbac2..66775fee56 100644 --- a/packages/gradle/src/utils/get-gradle-report.spec.ts +++ b/packages/gradle/src/utils/get-gradle-report.spec.ts @@ -1,6 +1,9 @@ import { readFileSync } from 'fs'; import { join } from 'path'; -import { processProjectReports } from './get-gradle-report'; +import { + processGradleDependencies, + processProjectReports, +} from './get-gradle-report'; describe('processProjectReports', () => { it('should process project reports', () => { @@ -46,3 +49,28 @@ describe('processProjectReports', () => { expect(report.gradleProjectToChildProjects.get('')).toEqual([]); }); }); + +describe('processGradleDependencies', () => { + it('should process gradle dependencies with composite build', () => { + const depFilePath = join( + __dirname, + '..', + 'utils/__mocks__/gradle-composite-dependencies.txt' + ); + const dependencies = processGradleDependencies(depFilePath); + expect(Array.from(dependencies)).toEqual([ + ':my-utils:number-utils', + ':my-utils:string-utils', + ]); + }); + + it('should process gradle dependencies with regular build', () => { + const depFilePath = join( + __dirname, + '..', + 'utils/__mocks__/gradle-dependencies.txt' + ); + const dependencies = processGradleDependencies(depFilePath); + expect(Array.from(dependencies)).toEqual([':utilities']); + }); +}); diff --git a/packages/gradle/src/utils/get-gradle-report.ts b/packages/gradle/src/utils/get-gradle-report.ts index f9de425ba8..ddb5006795 100644 --- a/packages/gradle/src/utils/get-gradle-report.ts +++ b/packages/gradle/src/utils/get-gradle-report.ts @@ -21,10 +21,10 @@ import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; export interface GradleReport { gradleFileToGradleProjectMap: Map; - buildFileToDepsMap: Map; + buildFileToDepsMap: Map>; gradleFileToOutputDirsMap: Map>; gradleProjectToTasksTypeMap: Map>; - gradleProjectToTasksMap: Map>; + gradleProjectToTasksMap: Map>; gradleProjectToProjectName: Map; gradleProjectNameToProjectRootMap: Map; gradleProjectToChildProjects: Map; @@ -33,10 +33,10 @@ export interface GradleReport { export interface GradleReportJSON { hash: string; gradleFileToGradleProjectMap: Record; - buildFileToDepsMap: Record; + buildFileToDepsMap: Record>; gradleFileToOutputDirsMap: Record>; gradleProjectToTasksTypeMap: Record>; - gradleProjectToTasksMap: Record>; + gradleProjectToTasksMap: Record>; gradleProjectToProjectName: Record; gradleProjectNameToProjectRootMap: Record; gradleProjectToChildProjects: Record; @@ -220,13 +220,13 @@ export function processProjectReports( * Map of Gradle Build File to tasks type map */ const gradleProjectToTasksTypeMap = new Map>(); - const gradleProjectToTasksMap = new Map>(); + const gradleProjectToTasksMap = new Map>(); const gradleProjectToProjectName = new Map(); const gradleProjectNameToProjectRootMap = new Map(); /** * Map of buildFile to dependencies report path */ - const buildFileToDepsMap = new Map(); + const buildFileToDepsMap = new Map>(); /** * Map fo possible output files of each gradle file * e.g. {build.gradle.kts: { projectReportDir: '' testReportDir: '' }} @@ -320,10 +320,13 @@ export function processProjectReports( relative(workspaceRoot, absBuildFilePath) ); const buildDir = relative(workspaceRoot, absBuildDirPath); - buildFileToDepsMap.set( - buildFile, - dependenciesMap.get(gradleProject) as string - ); + const depsFile = dependenciesMap.get(gradleProject); + if (depsFile) { + buildFileToDepsMap.set( + buildFile, + processGradleDependencies(depsFile) + ); + } outputDirMap.set('build', `{workspaceRoot}/${buildDir}`); outputDirMap.set( @@ -395,3 +398,42 @@ export function processProjectReports( gradleProjectToChildProjects, }; } + +export function processGradleDependencies(depsFile: string): Set { + const dependedProjects = new Set(); + const lines = readFileSync(depsFile).toString().split(newLineSeparator); + let inDeps = false; + for (const line of lines) { + if ( + line.startsWith('implementationDependenciesMetadata') || + line.startsWith('compileClasspath') + ) { + inDeps = true; + continue; + } + + if (inDeps) { + if (line === '') { + inDeps = false; + continue; + } + const [indents, dep] = line.split('--- '); + if (indents === '\\' || indents === '+') { + let targetProjectName: string | undefined; + if (dep.startsWith('project ')) { + targetProjectName = dep + .substring('project '.length) + .replace(/ \(n\)$/, '') + .trim(); + } else if (dep.includes('-> project')) { + const [_, projectName] = dep.split('-> project'); + targetProjectName = projectName.trim(); + } + if (targetProjectName) { + dependedProjects.add(targetProjectName); + } + } + } + } + return dependedProjects; +}