Skip to content

Commit

Permalink
feat(gradle): support composite build
Browse files Browse the repository at this point in the history
  • Loading branch information
xiongemi committed Jun 13, 2024
1 parent 73c8c33 commit c8c3ebd
Show file tree
Hide file tree
Showing 15 changed files with 435 additions and 69 deletions.
Binary file modified e2e/gradle/gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 2 additions & 3 deletions e2e/gradle/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
validateDistributionUrl=false
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
4 changes: 2 additions & 2 deletions e2e/gradle/src/gradle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ describe('Gradle', () => {
createFile(
`app2/build.gradle`,
`plugins {
id 'gradleProject.groovy-application-conventions'
id 'buildlogic.groovy-application-conventions'
}
dependencies {
Expand All @@ -64,7 +64,7 @@ dependencies {
createFile(
`app2/build.gradle.kts`,
`plugins {
id("gradleProject.kotlin-library-conventions")
id("buildlogic.kotlin-application-conventions")
}
dependencies {
Expand Down
9 changes: 8 additions & 1 deletion packages/gradle/migrations.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
{
"generators": {},
"generators": {
"add-project-report-all": {
"version": "19.3.0-beta.4",
"cli": "nx",
"description": "Add task projectReportAll to build.gradle file",
"factory": "./src/migrations/19-3-0/add-project-report-all"
}
},
"packageJsonUpdates": {}
}
8 changes: 8 additions & 0 deletions packages/gradle/migrations.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import json = require('./migrations.json');

import { assertValidMigrationPaths } from '@nx/devkit/internal-testing-utils';
import { MigrationsJson } from '@nx/devkit';

describe('gradle migrations', () => {
assertValidMigrationPaths(json as MigrationsJson, __dirname);
});
82 changes: 67 additions & 15 deletions packages/gradle/src/generators/init/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
addDependenciesToPackageJson,
formatFiles,
GeneratorCallback,
globAsync,
logger,
readNxJson,
runTasksInSerial,
Expand All @@ -12,6 +13,7 @@ import { execSync } from 'child_process';
import { nxVersion } from '../../utils/versions';
import { InitGeneratorSchema } from './schema';
import { hasGradlePlugin } from '../../utils/has-gradle-plugin';
import { dirname, join, basename } from 'path';

export async function initGenerator(tree: Tree, options: InitGeneratorSchema) {
const tasks: GeneratorCallback[] = [];
Expand All @@ -36,10 +38,9 @@ Running 'gradle init':`);
)
);
}

await addBuildGradleFileNextToSettingsGradle(tree);
addPlugin(tree);
updateNxJsonConfiguration(tree);
addProjectReportToBuildGradle(tree);

if (!options.skipFormat) {
await formatFiles(tree);
Expand All @@ -66,23 +67,44 @@ function addPlugin(tree: Tree) {
}

/**
* This function adds the project-report plugin to the build.gradle or build.gradle.kts file
* This function creates and populate build.gradle file next to the settings.gradle file.
*/
function addProjectReportToBuildGradle(tree: Tree) {
let buildGradleFile: string;
if (tree.exists('settings.gradle.kts')) {
buildGradleFile = 'build.gradle.kts';
} else if (tree.exists('settings.gradle')) {
buildGradleFile = 'build.gradle';
}
export async function addBuildGradleFileNextToSettingsGradle(tree: Tree) {
const settingsGradleFiles = await globAsync(tree, ['**/settings.gradle*']);
settingsGradleFiles.forEach((settingsGradleFile) => {
addProjectReportToBuildGradle(settingsGradleFile, tree);
});
}

/**
* - creates a build.gradle file next to the settings.gradle file if it does not exist.
* - adds the project-report plugin to the build.gradle file if it does not exist.
* - adds a task to generate project reports for all subprojects and included builds.
*/
function addProjectReportToBuildGradle(settingsGradleFile: string, tree: Tree) {
const filename = basename(settingsGradleFile);
let gradleFilePath;
if (filename === 'settings.gradle.kts') {
gradleFilePath = 'build.gradle.kts';
} else if (filename === 'settings.gradle') {
gradleFilePath = 'build.gradle';
} else {
logger.warn(
`Could not find 'settings.gradle' or 'settings.gradle.kts' file in your gradle workspace.`
);
return;
}
gradleFilePath = join(dirname(settingsGradleFile), gradleFilePath);
let buildGradleContent = '';
if (tree.exists(buildGradleFile)) {
buildGradleContent = tree.read(buildGradleFile).toString();
if (!tree.exists(gradleFilePath)) {
tree.write(gradleFilePath, buildGradleContent); // create a build.gradle file near settings.gradle file if it does not exist
} else {
buildGradleContent = tree.read(gradleFilePath).toString();
}

if (buildGradleContent.includes('allprojects')) {
if (!buildGradleContent.includes('"project-report')) {
logger.warn(`Please add the project-report plugin to your ${buildGradleFile}:
if (!buildGradleContent.includes('"project-report"')) {
logger.warn(`Please add the project-report plugin to your ${gradleFilePath}:
allprojects {
apply {
plugin("project-report")
Expand All @@ -95,7 +117,37 @@ allprojects {
plugin("project-report")
}
}`;
tree.write(buildGradleFile, buildGradleContent);
}

if (!buildGradleContent.includes(`tasks.register("projectReportAll")`)) {
if (gradleFilePath.endsWith('.kts')) {
buildGradleContent += `\n\rtasks.register("projectReportAll") {
// All project reports of subprojects
allprojects.forEach {
dependsOn(it.tasks.get("projectReport"))
}
// All projectReportAll of included builds
gradle.includedBuilds.forEach {
dependsOn(it.task(":projectReportAll"))
}
}`;
} else {
buildGradleContent += `\n\rtasks.register("projectReportAll") {
// All project reports of subprojects
allprojects.forEach {
dependsOn(it.tasks.getAt("projectReport"))
}
// All projectReportAll of included builds
gradle.includedBuilds.forEach {
dependsOn(it.task(":projectReportAll"))
}
}`;
}
}
if (buildGradleContent) {
tree.write(gradleFilePath, buildGradleContent);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { Tree } from '@nx/devkit';

import update from './add-project-report-all';

describe('AddProjectReportAll', () => {
let tree: Tree;

beforeAll(() => {
tree = createTreeWithEmptyWorkspace();
});

it('should update build.gradle', async () => {
tree.write('settings.gradle', '');
await update(tree);
const buildGradle = tree.read('build.gradle').toString();
expect(buildGradle).toContain('project-report');
expect(buildGradle).toContain('projectReportAll');
});

it('should update build.gradle.kts', async () => {
tree.write('settings.gradle.kts', '');
await update(tree);
const buildGradle = tree.read('build.gradle.kts').toString();
expect(buildGradle).toContain('project-report');
expect(buildGradle).toContain('projectReportAll');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Tree } from '@nx/devkit';
import { addBuildGradleFileNextToSettingsGradle } from '../../generators/init/init';

/**
* This migration adds task `projectReportAll` to build.gradle files
*/
export default async function update(tree: Tree) {
await addBuildGradleFileNextToSettingsGradle(tree);
}
72 changes: 72 additions & 0 deletions packages/gradle/src/plugin/dependencies.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { join } from 'path';
import { processGradleDependencies } from './dependencies';

jest.mock('@nx/devkit', () => ({
...jest.requireActual<any>('@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', 'number-utils'],
[':my-utils:string-utils', 'string-utils'],
]),
'app',
'app',
{} 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', 'number-utils'],
[':my-utils:string-utils', 'string-utils'],
[':utilities', 'utilities'],
]),
'app',
'app',
{} as any,
dependencies
);
expect(Array.from(dependencies)).toEqual([
{
source: 'app',
sourceFile: 'app',
target: 'utilities',
type: 'static',
},
]);
});
});
Loading

0 comments on commit c8c3ebd

Please sign in to comment.