Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gradle): add gradle init generator #22245

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 66 additions & 57 deletions e2e/gradle/src/gradle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,80 +8,89 @@ import {
runCommand,
uniq,
updateFile,
updateJson,
} from '@nx/e2e/utils';
import { execSync } from 'child_process';

describe('Gradle', () => {
let gradleProjectName = uniq('my-gradle-project');
describe.each([{ type: 'kotlin' }, { type: 'groovy' }])(
'$type',
({ type }: { type: 'kotlin' | 'groovy' }) => {
let gradleProjectName = uniq('my-gradle-project');
beforeAll(() => {
newProject();
createGradleProject(gradleProjectName, type);
});
afterAll(() => cleanupProject());

beforeAll(() => {
newProject();
createGradleProject(gradleProjectName);
});
afterAll(() => cleanupProject());
it('should build', () => {
const projects = runCLI(`show projects`);
expect(projects).toContain('app');
expect(projects).toContain('list');
expect(projects).toContain('utilities');
expect(projects).toContain(gradleProjectName);

it('should build', () => {
const projects = runCLI(`show projects`);
expect(projects).toContain('app');
expect(projects).toContain('list');
expect(projects).toContain('utilities');
expect(projects).toContain(gradleProjectName);
const buildOutput = runCLI('build app', { verbose: true });
// app depends on list and utilities
expect(buildOutput).toContain('nx run list:build');
expect(buildOutput).toContain('nx run utilities:build');

const buildOutput = runCLI('build app', { verbose: true });
// app depends on list and utilities
expect(buildOutput).toContain('nx run list:build');
expect(buildOutput).toContain('nx run utilities:build');
checkFilesExist(
`app/build/libs/app.jar`,
`list/build/libs/list.jar`,
`utilities/build/libs/utilities.jar`
);
});

checkFilesExist(
`app/build/libs/app.jar`,
`list/build/libs/list.jar`,
`utilities/build/libs/utilities.jar`
);
});
it('should track dependencies for new app', () => {
if (type === 'groovy') {
createFile(
`app2/build.gradle`,
`plugins {
id 'gradleProject.groovy-application-conventions'
}
it('should track dependencies for new app', () => {
createFile(
'app2/build.gradle.kts',
`
plugins {
id("gradleProject.kotlin-application-conventions")
}
dependencies {
implementation(project(":app"))
dependencies {
implementation project(':app')
}`
);
} else {
createFile(
`app2/build.gradle.kts`,
`plugins {
id("gradleProject.kotlin-library-conventions")
}
dependencies {
implementation(project(":app"))
}`
);
}
updateFile(
`settings.gradle${type === 'kotlin' ? '.kts' : ''}`,
(content) => {
content += `\r\ninclude("app2")`;
return content;
}
);
const buildOutput = runCLI('build app2', { verbose: true });
// app2 depends on app
expect(buildOutput).toContain('nx run app:build');
});
}
`
);
updateFile(`settings.gradle.kts`, (content) => {
content += `\r\ninclude("app2")`;
return content;
});
const buildOutput = runCLI('build app2', { verbose: true });
// app2 depends on app
expect(buildOutput).toContain('nx run app:build');
});
);
});

function createGradleProject(projectName: string) {
function createGradleProject(
projectName: string,
type: 'kotlin' | 'groovy' = 'kotlin'
) {
e2eConsoleLogger(`Using java version: ${execSync('java --version')}`);
e2eConsoleLogger(`Using gradle version: ${execSync('gradle --version')}`);
e2eConsoleLogger(execSync(`gradle help --task :init`).toString());
e2eConsoleLogger(
runCommand(
`gradle init --type kotlin-application --dsl kotlin --project-name ${projectName} --package gradleProject --no-incubating --split-project`
`gradle init --type ${type}-application --dsl ${type} --project-name ${projectName} --package gradleProject --no-incubating --split-project`
)
);
updateJson('nx.json', (nxJson) => {
nxJson.plugins = ['@nx/gradle'];
return nxJson;
});
createFile(
'build.gradle.kts',
`allprojects {
apply {
plugin("project-report")
}
}`
);
runCLI(`add @nx/gradle`);
}
11 changes: 11 additions & 0 deletions packages/gradle/generators.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "Nx Gradle",
"version": "0.1",
"generators": {
"init": {
"factory": "./src/generators/init/init#initGenerator",
"schema": "./src/generators/init/schema.json",
"description": "Initializes a Gradle project in the current workspace"
}
}
}
1 change: 1 addition & 0 deletions packages/gradle/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './plugin';
export { initGenerator } from './src/generators/init/init';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either don't export this for now. Or, expose it under /generators

8 changes: 8 additions & 0 deletions packages/gradle/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@
"url": "https://github.com/nrwl/nx/issues"
},
"homepage": "https://nx.dev",
"generators": "./generators.json",
"exports": {
".": "./index.js",
"./package.json": "./package.json",
"./migrations.json": "./migrations.json",
"./generators.json": "./generators.json",
"./plugin": "./plugin.js"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this.

},
"nx-migrate": {
"migrations": "./migrations.json"
},
Expand Down
73 changes: 73 additions & 0 deletions packages/gradle/src/generators/init/init.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { readNxJson, Tree, updateNxJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';

import { initGenerator } from './init';

describe('@nx/gradle:init', () => {
let tree: Tree;

beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
tree.write('settings.gradle', '');
});

it('should add the plugin', async () => {
await initGenerator(tree, {
skipFormat: true,
skipPackageJson: false,
});
const nxJson = readNxJson(tree);
expect(nxJson.plugins).toMatchInlineSnapshot(`
[
{
"options": {
"buildTargetName": "build",
"classesTargetName": "classes",
"testTargetName": "test",
},
"plugin": "@nx/gradle/plugin",
},
]
`);
});

it('should not overwrite existing plugins', async () => {
updateNxJson(tree, {
plugins: ['foo'],
});
await initGenerator(tree, {
skipFormat: true,
skipPackageJson: false,
});
const nxJson = readNxJson(tree);
expect(nxJson.plugins).toMatchInlineSnapshot(`
[
"foo",
{
"options": {
"buildTargetName": "build",
"classesTargetName": "classes",
"testTargetName": "test",
},
"plugin": "@nx/gradle/plugin",
},
]
`);
});

it('should not add plugin if already in array', async () => {
updateNxJson(tree, {
plugins: ['@nx/gradle/plugin'],
});
await initGenerator(tree, {
skipFormat: true,
skipPackageJson: false,
});
const nxJson = readNxJson(tree);
expect(nxJson.plugins).toMatchInlineSnapshot(`
[
"@nx/gradle/plugin",
]
`);
});
});
102 changes: 102 additions & 0 deletions packages/gradle/src/generators/init/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import {
addDependenciesToPackageJson,
formatFiles,
GeneratorCallback,
logger,
readNxJson,
runTasksInSerial,
Tree,
updateNxJson,
} from '@nx/devkit';
import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts';
import { createNodes } from '../../plugin/nodes';
import { nxVersion } from '../../utils/versions';
import { InitGeneratorSchema } from './schema';
import { hasGradlePlugin } from '../../utils/has-gradle-plugin';

export async function initGenerator(tree: Tree, options: InitGeneratorSchema) {
const tasks: GeneratorCallback[] = [];

if (!options.skipPackageJson && tree.exists('package.json')) {
tasks.push(
addDependenciesToPackageJson(
tree,
{},
{
'@nx/gradle': nxVersion,
},
undefined,
options.keepExistingVersions
)
);
}

addPlugin(tree);
addProjectReportToBuildGradle(tree);

if (options.updatePackageScripts && tree.exists('package.json')) {
await updatePackageScripts(tree, createNodes);
}

if (!options.skipFormat) {
await formatFiles(tree);
}

return runTasksInSerial(...tasks);
}

function addPlugin(tree: Tree) {
const nxJson = readNxJson(tree);

if (!hasGradlePlugin(tree)) {
nxJson.plugins ??= [];
nxJson.plugins.push({
plugin: '@nx/gradle/plugin',
options: {
testTargetName: 'test',
classesTargetName: 'classes',
buildTargetName: 'build',
},
});
updateNxJson(tree, nxJson);
}
}

/**
* This function adds the project-report plugin to the build.gradle or build.gradle.kts 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';
} else {
throw new Error(
'Could not find settings.gradle or settings.gradle.kts file in your gradle workspace.'
);
}
let buildGradleContent = '';
if (tree.exists(buildGradleFile)) {
buildGradleContent = tree.read(buildGradleFile).toString();
}
if (buildGradleContent.includes('allprojects')) {
if (!buildGradleContent.includes('"project-report')) {
logger.warn(`Please add the project-report plugin to your ${buildGradleFile}:
allprojects {
apply {
plugin("project-report")
}
}`);
}
} else {
buildGradleContent += `\n\rallprojects {
apply {
plugin("project-report")
}
}`;
tree.write(buildGradleFile, buildGradleContent);
}
}

export default initGenerator;
6 changes: 6 additions & 0 deletions packages/gradle/src/generators/init/schema.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface InitGeneratorSchema {
skipFormat?: boolean;
skipPackageJson?: boolean;
keepExistingVersions?: boolean;
updatePackageScripts?: boolean;
}
34 changes: 34 additions & 0 deletions packages/gradle/src/generators/init/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"$schema": "https://json-schema.org/schema",
"$id": "NxGradleInitSchema",
"title": "Gradle Init Generator",
"description": "Initializes a Gradle project in the current workspace.",
"type": "object",
"properties": {
"skipFormat": {
"description": "Skip formatting files.",
"type": "boolean",
"default": false,
"x-priority": "internal"
},
"skipPackageJson": {
"type": "boolean",
"default": false,
"description": "Do not add dependencies to `package.json`.",
"x-priority": "internal"
},
"keepExistingVersions": {
"type": "boolean",
"x-priority": "internal",
"description": "Keep existing dependencies versions",
"default": false
},
"updatePackageScripts": {
"type": "boolean",
"x-priority": "internal",
"description": "Update `package.json` scripts with inferred targets",
"default": false
}
},
"required": []
}
Loading