feat(java): add gradle kotlin plugin (#29464)
- [x] change init to create `createNodes` instead - [x] unit tests - [x] test-ci - [x] test on windows - [x] help metadata - [x] external nodes TODO: - add publish executor? - publish to maven central? <!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> currently, it uses [project report plugin](https://docs.gradle.org/current/userguide/project_report_plugin.html). - pro: no need to maintain this plugin - con: this plugin gives limited information ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> change the project report plugin to @nxn/gradle/plugin-v1 now the @nx/gradle plugin will use project graph plugin (dev.nx.gradle.project-graph) created in this pr. this plugin will create json file that is exactly what nx project grpah expected. ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
This commit is contained in:
parent
296f326b94
commit
b377c96d99
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@ -65,6 +65,12 @@ jobs:
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 21
|
||||
|
||||
- name: Check Documentation
|
||||
run: pnpm nx documentation
|
||||
timeout-minutes: 20
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@ -67,5 +67,8 @@ target
|
||||
|
||||
vite.config.*.timestamp*
|
||||
|
||||
|
||||
storybook-static
|
||||
|
||||
# Ignore Gradle project-specific cache directory
|
||||
.gradle
|
||||
.kotlin
|
||||
|
||||
@ -64,6 +64,13 @@ launch-templates:
|
||||
- name: Load Cargo Env
|
||||
script: echo "PATH=$HOME/.cargo/bin:$PATH" >> $NX_CLOUD_ENV
|
||||
|
||||
- name: Setup Java 21
|
||||
script: |
|
||||
sudo apt update
|
||||
sudo apt install -y openjdk-21-jdk
|
||||
sudo update-alternatives --set java /usr/lib/jvm/java-21-openjdk-amd64/bin/java
|
||||
java -version
|
||||
|
||||
linux-extra-large:
|
||||
resource-class: 'docker_linux_amd64/extra_large'
|
||||
image: 'ubuntu22.04-node20.11-v10'
|
||||
@ -128,3 +135,10 @@ launch-templates:
|
||||
|
||||
- name: Load Cargo Env
|
||||
script: echo "PATH=$HOME/.cargo/bin:$PATH" >> $NX_CLOUD_ENV
|
||||
|
||||
- name: Setup Java 21
|
||||
script: |
|
||||
sudo apt update
|
||||
sudo apt install -y openjdk-21-jdk
|
||||
sudo update-alternatives --set java /usr/lib/jvm/java-21-openjdk-amd64/bin/java
|
||||
java -version
|
||||
|
||||
@ -13,6 +13,7 @@ packages/express/src/schematics/**/files/**/*.json
|
||||
packages/nest/src/schematics/**/files/**/*.json
|
||||
packages/react/src/schematics/**/files/**/*.json
|
||||
packages/jest/src/schematics/**/files/**/*.json
|
||||
packages/gradle/project-graph/build/**/*.*
|
||||
packages/nx/src/plugins/js/lock-file/__fixtures__/**/*.*
|
||||
packages/**/schematics/**/files/**/*.html
|
||||
packages/**/generators/**/files/**/*.html
|
||||
|
||||
6
build.gradle.kts
Normal file
6
build.gradle.kts
Normal file
@ -0,0 +1,6 @@
|
||||
plugins {
|
||||
id("dev.nx.gradle.project-graph") version("0.0.2")
|
||||
id("com.ncorti.ktfmt.gradle") version("+")
|
||||
}
|
||||
|
||||
group = "dev.nx"
|
||||
@ -2325,6 +2325,16 @@
|
||||
}
|
||||
},
|
||||
"migrations": {
|
||||
"/nx-api/gradle/migrations/change-plugin-to-v1": {
|
||||
"description": "Change @nx/gradle plugin to version 1",
|
||||
"file": "generated/packages/gradle/migrations/change-plugin-to-v1.json",
|
||||
"hidden": false,
|
||||
"name": "change-plugin-to-v1",
|
||||
"version": "21.0.0-beta.5",
|
||||
"originalFilePath": "/packages/gradle",
|
||||
"path": "/nx-api/gradle/migrations/change-plugin-to-v1",
|
||||
"type": "migration"
|
||||
},
|
||||
"/nx-api/gradle/migrations/add-include-subprojects-tasks": {
|
||||
"description": "Add includeSubprojectsTasks to build.gradle file",
|
||||
"file": "generated/packages/gradle/migrations/add-include-subprojects-tasks.json",
|
||||
|
||||
@ -2309,6 +2309,16 @@
|
||||
}
|
||||
],
|
||||
"migrations": [
|
||||
{
|
||||
"description": "Change @nx/gradle plugin to version 1",
|
||||
"file": "generated/packages/gradle/migrations/change-plugin-to-v1.json",
|
||||
"hidden": false,
|
||||
"name": "change-plugin-to-v1",
|
||||
"version": "21.0.0-beta.5",
|
||||
"originalFilePath": "/packages/gradle",
|
||||
"path": "gradle/migrations/change-plugin-to-v1",
|
||||
"type": "migration"
|
||||
},
|
||||
{
|
||||
"description": "Add includeSubprojectsTasks to build.gradle file",
|
||||
"file": "generated/packages/gradle/migrations/add-include-subprojects-tasks.json",
|
||||
|
||||
@ -10,5 +10,5 @@
|
||||
"path": "/packages/gradle",
|
||||
"schema": null,
|
||||
"type": "migration",
|
||||
"examplesFile": "#### Add includeSubprojectsTasks to build.gradle File\n\nAdd includeSubprojectsTasks to build.gradle file\n\n#### Sample Code Changes\n\nUpdate import paths for `withModuleFederation` and `withModuleFederationForSSR`.\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```json {% fileName=\"nx.json\" %}\n{\n \"plugins\": [\"@nx/gradle\"]\n}\n```\n\n{% /tab %}\n{% tab label=\"After\" %}\n\n```json {% highlightLines=[5] fileName=\"nx.json\" %}\n{\n \"plugins\": [\n {\n \"options\": {\n \"includeSubprojectsTasks\": true\n },\n \"plugin\": \"@nx/gradle\"\n }\n ]\n}\n```\n\n{% /tab %}\n{% /tabs %}\n"
|
||||
"examplesFile": "#### Add includeSubprojectsTasks to @nx/gradle Plugin Options\n\nAdd includeSubprojectsTasks to @nx/gradle plugin options in nx.json file\n\n#### Sample Code Changes\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```json {% fileName=\"nx.json\" %}\n{\n \"plugins\": [\"@nx/gradle\"]\n}\n```\n\n{% /tab %}\n{% tab label=\"After\" %}\n\n```json {% highlightLines=[5] fileName=\"nx.json\" %}\n{\n \"plugins\": [\n {\n \"options\": {\n \"includeSubprojectsTasks\": true\n },\n \"plugin\": \"@nx/gradle\"\n }\n ]\n}\n```\n\n{% /tab %}\n{% /tabs %}\n"
|
||||
}
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "change-plugin-to-v1",
|
||||
"version": "21.0.0-beta.5",
|
||||
"cli": "nx",
|
||||
"description": "Change @nx/gradle plugin to version 1",
|
||||
"factory": "./src/migrations/21-0-0/change-plugin-to-v1",
|
||||
"implementation": "/packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.ts",
|
||||
"aliases": [],
|
||||
"hidden": false,
|
||||
"path": "/packages/gradle",
|
||||
"schema": null,
|
||||
"type": "migration",
|
||||
"examplesFile": "#### Change @nx/gradle plugin to @nx/gradle/plugin-v1\n\nChange @nx/gradle plugin to version 1 in nx.json\n\n#### Sample Code Changes\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```json {% fileName=\"nx.json\" %}\n{\n \"plugins\": [\"@nx/gradle\"]\n}\n```\n\n{% /tab %}\n{% tab label=\"After\" %}\n\n```json {% highlightLines=[5] fileName=\"nx.json\" %}\n{\n \"plugins\": [\"@nx/gradle/plugin-v1\"]\n}\n```\n\n{% /tab %}\n{% /tabs %}\n"
|
||||
}
|
||||
@ -375,10 +375,10 @@ jobs:
|
||||
# Uncomment this line to enable task distribution
|
||||
# - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-jvm" --stop-agents-after="build"
|
||||
|
||||
- name: Set up JDK 17 for x64
|
||||
- name: Set up JDK 21 for x64
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
architecture: x64
|
||||
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
# This file was generated by the Gradle 'init' task.
|
||||
# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format
|
||||
BIN
e2e/gradle/gradle/wrapper/gradle-wrapper.jar
vendored
BIN
e2e/gradle/gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
@ -17,10 +17,9 @@ import { createGradleProject } from './utils/create-gradle-project';
|
||||
import { createFileSync } from 'fs-extra';
|
||||
|
||||
describe('Nx Import Gradle', () => {
|
||||
let proj: string;
|
||||
const tempImportE2ERoot = join(e2eCwd, 'nx-import');
|
||||
beforeAll(() => {
|
||||
proj = newProject({
|
||||
newProject({
|
||||
packages: ['@nx/js'],
|
||||
});
|
||||
|
||||
@ -66,30 +65,7 @@ describe('Nx Import Gradle', () => {
|
||||
'gradleProjectKotlin',
|
||||
'kotlin-'
|
||||
);
|
||||
// Add project.json files to the gradle project to avoid duplicate project names
|
||||
createFileSync(join(tempGraldeProjectPath, 'project.json'));
|
||||
writeFileSync(
|
||||
join(tempGraldeProjectPath, 'project.json'),
|
||||
`{"name": "${tempGradleProjectName}"}`
|
||||
);
|
||||
|
||||
execSync(`git init`, {
|
||||
cwd: tempGraldeProjectPath,
|
||||
});
|
||||
execSync(`git add .`, {
|
||||
cwd: tempGraldeProjectPath,
|
||||
});
|
||||
execSync(`git commit -am "initial commit"`, {
|
||||
cwd: tempGraldeProjectPath,
|
||||
});
|
||||
|
||||
try {
|
||||
execSync(`git checkout -b main`, {
|
||||
cwd: tempGraldeProjectPath,
|
||||
});
|
||||
} catch {
|
||||
// This fails if git is already configured to have `main` branch, but that's OK
|
||||
}
|
||||
setupGradleProjectGit(tempGraldeProjectPath, tempGradleProjectName);
|
||||
|
||||
const remote = tempGraldeProjectPath;
|
||||
const ref = 'main';
|
||||
@ -140,30 +116,7 @@ describe('Nx Import Gradle', () => {
|
||||
'gradleProjectGroovy',
|
||||
'groovy-'
|
||||
);
|
||||
// Add project.json files to the gradle project to avoid duplicate project names
|
||||
createFileSync(join(tempGraldeProjectPath, 'project.json'));
|
||||
writeFileSync(
|
||||
join(tempGraldeProjectPath, 'project.json'),
|
||||
`{"name": "${tempGradleProjectName}"}`
|
||||
);
|
||||
|
||||
execSync(`git init`, {
|
||||
cwd: tempGraldeProjectPath,
|
||||
});
|
||||
execSync(`git add .`, {
|
||||
cwd: tempGraldeProjectPath,
|
||||
});
|
||||
execSync(`git commit -am "initial commit"`, {
|
||||
cwd: tempGraldeProjectPath,
|
||||
});
|
||||
|
||||
try {
|
||||
execSync(`git checkout -b main`, {
|
||||
cwd: tempGraldeProjectPath,
|
||||
});
|
||||
} catch {
|
||||
// This fails if git is already configured to have `main` branch, but that's OK
|
||||
}
|
||||
setupGradleProjectGit(tempGraldeProjectPath, tempGradleProjectName);
|
||||
|
||||
const remote = tempGraldeProjectPath;
|
||||
const ref = 'main';
|
||||
@ -199,3 +152,40 @@ describe('Nx Import Gradle', () => {
|
||||
runCommand(`git commit -am 'import groovy project'`);
|
||||
});
|
||||
});
|
||||
|
||||
function setupGradleProjectGit(
|
||||
tempGraldeProjectPath: string,
|
||||
tempGradleProjectName: string
|
||||
) {
|
||||
// Add project.json files to the gradle project to avoid duplicate project names
|
||||
createFileSync(join(tempGraldeProjectPath, 'project.json'));
|
||||
writeFileSync(
|
||||
join(tempGraldeProjectPath, 'project.json'),
|
||||
`{"name": "${tempGradleProjectName}"}`
|
||||
);
|
||||
|
||||
execSync(`./gradlew --stop`, {
|
||||
cwd: tempGraldeProjectPath,
|
||||
});
|
||||
execSync(`./gradlew clean`, {
|
||||
cwd: tempGraldeProjectPath,
|
||||
});
|
||||
|
||||
execSync(`git init`, {
|
||||
cwd: tempGraldeProjectPath,
|
||||
});
|
||||
execSync(`git add .`, {
|
||||
cwd: tempGraldeProjectPath,
|
||||
});
|
||||
execSync(`git commit -am "initial commit"`, {
|
||||
cwd: tempGraldeProjectPath,
|
||||
});
|
||||
|
||||
try {
|
||||
execSync(`git checkout -b main`, {
|
||||
cwd: tempGraldeProjectPath,
|
||||
});
|
||||
} catch {
|
||||
// This fails if git is already configured to have `main` branch, but that's OK
|
||||
}
|
||||
}
|
||||
|
||||
177
e2e/gradle/src/gradle-plugin-v1.test.ts
Normal file
177
e2e/gradle/src/gradle-plugin-v1.test.ts
Normal file
@ -0,0 +1,177 @@
|
||||
import {
|
||||
checkFilesExist,
|
||||
cleanupProject,
|
||||
createFile,
|
||||
fileExists,
|
||||
newProject,
|
||||
readFile,
|
||||
runCLI,
|
||||
uniq,
|
||||
updateFile,
|
||||
updateJson,
|
||||
} from '@nx/e2e/utils';
|
||||
import { basename, dirname, join } from 'path';
|
||||
|
||||
import { createGradleProject } from './utils/create-gradle-project';
|
||||
|
||||
describe('Gradle Plugin V1', () => {
|
||||
describe.each([{ type: 'kotlin' }, { type: 'groovy' }])(
|
||||
'$type',
|
||||
({ type }: { type: 'kotlin' | 'groovy' }) => {
|
||||
let gradleProjectName = uniq('my-gradle-project');
|
||||
beforeAll(() => {
|
||||
newProject();
|
||||
createGradleProject(gradleProjectName, type);
|
||||
runCLI(`add @nx/gradle`);
|
||||
updateJson('nx.json', (json) => {
|
||||
json.plugins.find((p) => p.plugin === '@nx/gradle').plugin =
|
||||
'@nx/gradle/plugin-v1';
|
||||
return json;
|
||||
});
|
||||
addProjectReportToBuildGradle(
|
||||
`settings.gradle${type === 'kotlin' ? '.kts' : ''}`
|
||||
);
|
||||
});
|
||||
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);
|
||||
|
||||
const buildOutput = runCLI('build app', { verbose: true });
|
||||
expect(buildOutput).toContain('nx run list:build');
|
||||
expect(buildOutput).toContain(':list:classes');
|
||||
expect(buildOutput).toContain('nx run utilities:build');
|
||||
expect(buildOutput).toContain(':utilities:classes');
|
||||
|
||||
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 'buildlogic.groovy-application-conventions'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':app')
|
||||
}`
|
||||
);
|
||||
} else {
|
||||
createFile(
|
||||
`app2/build.gradle.kts`,
|
||||
`plugins {
|
||||
id("buildlogic.kotlin-application-conventions")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":app"))
|
||||
}`
|
||||
);
|
||||
updateFile(`app/build.gradle.kts`, (content) => {
|
||||
content += `\r\ntasks.register("task1"){
|
||||
println("REGISTER TASK1: This is executed during the configuration phase")
|
||||
}`;
|
||||
return content;
|
||||
});
|
||||
}
|
||||
updateFile(
|
||||
`settings.gradle${type === 'kotlin' ? '.kts' : ''}`,
|
||||
(content) => {
|
||||
content += `\r\ninclude("app2")`;
|
||||
return content;
|
||||
}
|
||||
);
|
||||
|
||||
let buildOutput = runCLI('build app2', { verbose: true });
|
||||
// app2 depends on app
|
||||
expect(buildOutput).toContain('nx run app:build');
|
||||
expect(buildOutput).toContain(':app:classes');
|
||||
expect(buildOutput).toContain('nx run list:build');
|
||||
expect(buildOutput).toContain(':list:classes');
|
||||
expect(buildOutput).toContain('nx run utilities:build');
|
||||
expect(buildOutput).toContain(':utilities:classes');
|
||||
|
||||
checkFilesExist(
|
||||
`app2/build/libs/app2.jar`,
|
||||
`app/build/libs/app.jar`,
|
||||
`list/build/libs/list.jar`,
|
||||
`utilities/build/libs/utilities.jar`
|
||||
);
|
||||
});
|
||||
|
||||
it('should run atomized test target', () => {
|
||||
updateJson('nx.json', (json) => {
|
||||
json.plugins.find((p) => p.plugin === '@nx/gradle/plugin-v1').options[
|
||||
'ciTargetName'
|
||||
] = 'test-ci';
|
||||
return json;
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
runCLI('run app:test-ci--MessageUtilsTest', { verbose: true });
|
||||
runCLI('run list:test-ci--LinkedListTest', { verbose: true });
|
||||
}).not.toThrow();
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
function addProjectReportToBuildGradle(settingsGradleFile: string) {
|
||||
const filename = basename(settingsGradleFile);
|
||||
let gradleFilePath = 'build.gradle';
|
||||
if (filename.endsWith('.kts')) {
|
||||
gradleFilePath = 'build.gradle.kts';
|
||||
}
|
||||
gradleFilePath = join(dirname(settingsGradleFile), gradleFilePath);
|
||||
let buildGradleContent = '';
|
||||
if (!fileExists(gradleFilePath)) {
|
||||
createFile(gradleFilePath, buildGradleContent); // create a build.gradle file near settings.gradle file if it does not exist
|
||||
} else {
|
||||
buildGradleContent = readFile(gradleFilePath).toString();
|
||||
}
|
||||
|
||||
buildGradleContent += `\n\rallprojects {
|
||||
apply {
|
||||
plugin("project-report")
|
||||
}
|
||||
}`;
|
||||
|
||||
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) {
|
||||
updateFile(gradleFilePath, buildGradleContent);
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,7 @@ import {
|
||||
runCLI,
|
||||
uniq,
|
||||
updateFile,
|
||||
updateJson,
|
||||
} from '@nx/e2e/utils';
|
||||
|
||||
import { createGradleProject } from './utils/create-gradle-project';
|
||||
@ -30,9 +31,9 @@ describe('Gradle', () => {
|
||||
expect(projects).toContain(gradleProjectName);
|
||||
|
||||
const buildOutput = runCLI('build app', { verbose: true });
|
||||
expect(buildOutput).toContain('nx run list:build');
|
||||
expect(buildOutput).toContain('nx run list:');
|
||||
expect(buildOutput).toContain(':list:classes');
|
||||
expect(buildOutput).toContain('nx run utilities:build');
|
||||
expect(buildOutput).toContain('nx run utilities:');
|
||||
expect(buildOutput).toContain(':utilities:classes');
|
||||
|
||||
checkFilesExist(
|
||||
@ -82,8 +83,28 @@ dependencies {
|
||||
|
||||
let buildOutput = runCLI('build app2', { verbose: true });
|
||||
// app2 depends on app
|
||||
expect(buildOutput).toContain('nx run app:build');
|
||||
expect(buildOutput).toContain('nx run app:');
|
||||
expect(buildOutput).toContain(':app:classes');
|
||||
expect(buildOutput).toContain('nx run list:');
|
||||
expect(buildOutput).toContain(':list:classes');
|
||||
expect(buildOutput).toContain('nx run utilities:');
|
||||
expect(buildOutput).toContain(':utilities:classes');
|
||||
|
||||
checkFilesExist(`app2/build/libs/app2.jar`);
|
||||
});
|
||||
|
||||
it('should run atomized test target', () => {
|
||||
updateJson('nx.json', (json) => {
|
||||
json.plugins.find((p) => p.plugin === '@nx/gradle').options[
|
||||
'ciTargetName'
|
||||
] = 'test-ci';
|
||||
return json;
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
runCLI('run app:test-ci--MessageUtilsTest', { verbose: true });
|
||||
runCLI('run list:test-ci--LinkedListTest', { verbose: true });
|
||||
}).not.toThrow();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
tmpProjPath,
|
||||
} from '@nx/e2e/utils';
|
||||
import { execSync } from 'child_process';
|
||||
import { readFileSync } from 'fs';
|
||||
import { createFileSync, writeFileSync } from 'fs-extra';
|
||||
import { join, resolve } from 'path';
|
||||
|
||||
@ -15,14 +16,10 @@ export function createGradleProject(
|
||||
packageName: string = 'gradleProject',
|
||||
addProjectJsonNamePrefix: string = ''
|
||||
) {
|
||||
e2eConsoleLogger(
|
||||
`Using java version: ${execSync('java -version')} ${execSync(
|
||||
'echo $JAVA_HOME'
|
||||
)}`
|
||||
);
|
||||
e2eConsoleLogger(`Using java version: ${execSync('java -version')}`);
|
||||
const gradleCommand = isWindows()
|
||||
? resolve(`${__dirname}/../../gradlew.bat`)
|
||||
: resolve(`${__dirname}/../../gradlew`);
|
||||
? resolve(`${__dirname}/../../../../gradlew.bat`)
|
||||
: resolve(`${__dirname}/../../../../gradlew`);
|
||||
e2eConsoleLogger(
|
||||
'Using gradle version: ' +
|
||||
execSync(`${gradleCommand} --version`, {
|
||||
@ -36,13 +33,26 @@ export function createGradleProject(
|
||||
);
|
||||
e2eConsoleLogger(
|
||||
runCommand(
|
||||
`${gradleCommand} init --type ${type}-application --dsl ${type} --project-name ${projectName} --package ${packageName} --no-incubating --split-project`,
|
||||
`${gradleCommand} init --type ${type}-application --dsl ${type} --project-name ${projectName} --package ${packageName} --no-incubating --split-project --overwrite`,
|
||||
{
|
||||
cwd,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
e2eConsoleLogger(
|
||||
runCommand(`${gradleCommand} --stop`, {
|
||||
cwd,
|
||||
})
|
||||
);
|
||||
e2eConsoleLogger(
|
||||
runCommand(`${gradleCommand} clean`, {
|
||||
cwd,
|
||||
})
|
||||
);
|
||||
} catch (e) {}
|
||||
|
||||
if (addProjectJsonNamePrefix) {
|
||||
createFileSync(join(cwd, 'app/project.json'));
|
||||
writeFileSync(
|
||||
@ -60,4 +70,35 @@ export function createGradleProject(
|
||||
`{"name": "${addProjectJsonNamePrefix}utilities"}`
|
||||
);
|
||||
}
|
||||
|
||||
addLocalPluginManagement(
|
||||
join(cwd, `settings.gradle${type === 'kotlin' ? '.kts' : ''}`)
|
||||
);
|
||||
addLocalPluginManagement(
|
||||
join(cwd, `buildSrc/settings.gradle${type === 'kotlin' ? '.kts' : ''}`)
|
||||
);
|
||||
|
||||
e2eConsoleLogger(
|
||||
execSync(
|
||||
`${gradleCommand} :project-graph:publishToMavenLocal -x :project-graph:signNxProjectGraphPluginPluginMarkerMavenPublication -x :project-graph:signPluginMavenPublication -x :project-graph:publishNxProjectGraphPluginPluginMarkerMavenPublicationToMavenLocal -x :project-graph:publishPluginMavenPublicationToMavenLocal`,
|
||||
{
|
||||
cwd: `${__dirname}/../../../..`,
|
||||
}
|
||||
).toString()
|
||||
);
|
||||
}
|
||||
|
||||
function addLocalPluginManagement(filePath: string) {
|
||||
let content = readFileSync(filePath).toString();
|
||||
content =
|
||||
`pluginManagement {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
// Add other repositories if needed
|
||||
}
|
||||
}
|
||||
` + content;
|
||||
writeFileSync(filePath, content);
|
||||
}
|
||||
|
||||
8
gradle.properties
Normal file
8
gradle.properties
Normal file
@ -0,0 +1,8 @@
|
||||
# This file was generated by the Gradle 'init' task.
|
||||
# https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties
|
||||
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
# disable the configuration cache for this project https://docs.gradle.org/current/userguide/configuration_cache.html#config_cache:requirements:disallowed_types
|
||||
# nxProjectGraph is not supported by the configuration cache
|
||||
org.gradle.configuration-cache=false
|
||||
11
gradle/libs.versions.toml
Normal file
11
gradle/libs.versions.toml
Normal file
@ -0,0 +1,11 @@
|
||||
# This file was generated by the Gradle 'init' task.
|
||||
# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format
|
||||
|
||||
[plugins]
|
||||
jvm = { id = "org.jetbrains.kotlin.jvm", version = "1.9.20" }
|
||||
|
||||
[versions]
|
||||
kotlin-gradle-plugin = "2.0.21"
|
||||
|
||||
[libraries]
|
||||
kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin-gradle-plugin" }
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
@ -1,6 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
validateDistributionUrl=false
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
8
e2e/gradle/gradlew → gradlew
vendored
8
e2e/gradle/gradlew → gradlew
vendored
@ -15,6 +15,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
@ -55,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@ -84,7 +86,7 @@ done
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@ -203,7 +205,7 @@ fi
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
22
e2e/gradle/gradlew.bat → gradlew.bat
vendored
22
e2e/gradle/gradlew.bat → gradlew.bat
vendored
@ -13,6 +13,8 @@
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@ -369,6 +369,7 @@
|
||||
"core-js": "3.36.1",
|
||||
"enquirer": "~2.3.6",
|
||||
"fast-glob": "3.3.3",
|
||||
"form-data": "^4.0.2",
|
||||
"framer-motion": "^11.3.0",
|
||||
"front-matter": "^4.0.2",
|
||||
"glob": "7.1.4",
|
||||
|
||||
@ -27,7 +27,12 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["./package.json"],
|
||||
"files": [
|
||||
"./package.json",
|
||||
"./generators.json",
|
||||
"./executors.json",
|
||||
"./migrations.json"
|
||||
],
|
||||
"parser": "jsonc-eslint-parser",
|
||||
"rules": {
|
||||
"@nx/nx-plugin-checks": "error"
|
||||
|
||||
3
packages/gradle/executors.json
Normal file
3
packages/gradle/executors.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"executors": {}
|
||||
}
|
||||
@ -17,6 +17,12 @@
|
||||
"cli": "nx",
|
||||
"description": "Add includeSubprojectsTasks to build.gradle file",
|
||||
"factory": "./src/migrations/20-2-0/add-include-subprojects-tasks"
|
||||
},
|
||||
"change-plugin-to-v1": {
|
||||
"version": "21.0.0-beta.5",
|
||||
"cli": "nx",
|
||||
"description": "Change @nx/gradle plugin to version 1",
|
||||
"factory": "./src/migrations/21-0-0/change-plugin-to-v1"
|
||||
}
|
||||
},
|
||||
"packageJsonUpdates": {}
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
"generators": "./generators.json",
|
||||
"exports": {
|
||||
".": "./index.js",
|
||||
"./plugin-v1": "./plugin-v1.js",
|
||||
"./package.json": "./package.json",
|
||||
"./migrations.json": "./migrations.json",
|
||||
"./generators.json": "./generators.json"
|
||||
@ -38,5 +39,6 @@
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
},
|
||||
"executors": "./executors.json"
|
||||
}
|
||||
|
||||
131
packages/gradle/plugin-v1.spec.ts
Normal file
131
packages/gradle/plugin-v1.spec.ts
Normal file
@ -0,0 +1,131 @@
|
||||
import { CreateNodesContext } from '@nx/devkit';
|
||||
import { TempFs } from '@nx/devkit/internal-testing-utils';
|
||||
import { createNodesV2 } from './plugin-v1';
|
||||
import { type GradleReport } from './src/plugin-v1/utils/get-gradle-report';
|
||||
|
||||
let gradleReport: GradleReport;
|
||||
jest.mock('./src/plugin-v1/utils/get-gradle-report', () => {
|
||||
return {
|
||||
GRADLE_BUILD_FILES: new Set(['build.gradle', 'build.gradle.kts']),
|
||||
populateGradleReport: jest.fn().mockImplementation(() => void 0),
|
||||
getCurrentGradleReport: jest.fn().mockImplementation(() => gradleReport),
|
||||
};
|
||||
});
|
||||
|
||||
describe('@nx/gradle/plugin-v1', () => {
|
||||
let createNodesFunction = createNodesV2[1];
|
||||
let context: CreateNodesContext;
|
||||
let tempFs: TempFs;
|
||||
|
||||
beforeEach(async () => {
|
||||
tempFs = new TempFs('gradle-plugin');
|
||||
gradleReport = {
|
||||
gradleFileToGradleProjectMap: new Map<string, string>([
|
||||
['proj/build.gradle', 'proj'],
|
||||
]),
|
||||
gradleProjectToDepsMap: new Map<string, Set<string>>(),
|
||||
gradleFileToOutputDirsMap: new Map<string, Map<string, string>>([
|
||||
['proj/build.gradle', new Map([['build', 'build']])],
|
||||
]),
|
||||
gradleProjectToTasksMap: new Map<string, Set<string>>([
|
||||
['proj', new Set(['test'])],
|
||||
]),
|
||||
gradleProjectToTasksTypeMap: new Map<string, Map<string, string>>([
|
||||
['proj', new Map([['test', 'Verification']])],
|
||||
]),
|
||||
gradleProjectToProjectName: new Map<string, string>([['proj', 'proj']]),
|
||||
gradleProjectNameToProjectRootMap: new Map<string, string>([
|
||||
['proj', 'proj'],
|
||||
]),
|
||||
gradleProjectToChildProjects: new Map<string, string[]>(),
|
||||
};
|
||||
context = {
|
||||
nxJsonConfiguration: {
|
||||
namedInputs: {
|
||||
default: ['{projectRoot}/**/*'],
|
||||
production: ['!{projectRoot}/**/*.spec.ts'],
|
||||
},
|
||||
},
|
||||
workspaceRoot: tempFs.tempDir,
|
||||
configFiles: [],
|
||||
};
|
||||
tempFs.createFileSync('package.json', JSON.stringify({ name: 'repo' }));
|
||||
tempFs.createFileSync(
|
||||
'my-app/project.json',
|
||||
JSON.stringify({ name: 'my-app' })
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetModules();
|
||||
tempFs.cleanup();
|
||||
tempFs = null;
|
||||
});
|
||||
|
||||
it('should create nodes', async () => {
|
||||
tempFs.createFileSync('gradlew', '');
|
||||
|
||||
const nodes = await createNodesFunction(
|
||||
['gradlew', 'proj/build.gradle'],
|
||||
undefined,
|
||||
context
|
||||
);
|
||||
|
||||
expect(nodes).toMatchInlineSnapshot(`
|
||||
[
|
||||
[
|
||||
"proj/build.gradle",
|
||||
{
|
||||
"projects": {
|
||||
"proj": {
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"Verification": [
|
||||
"test",
|
||||
],
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"name": "proj",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"test": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:test",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
2
packages/gradle/plugin-v1.ts
Normal file
2
packages/gradle/plugin-v1.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { createDependencies } from './src/plugin-v1/dependencies';
|
||||
export { createNodes, createNodesV2 } from './src/plugin-v1/nodes';
|
||||
@ -1,14 +1,17 @@
|
||||
import { CreateNodesContext } from '@nx/devkit';
|
||||
import { CreateNodesContext, readJsonFile } from '@nx/devkit';
|
||||
import { TempFs } from '@nx/devkit/internal-testing-utils';
|
||||
import { createNodesV2 } from './plugin';
|
||||
import { type GradleReport } from './src/utils/get-gradle-report';
|
||||
import { type ProjectGraphReport } from './src/plugin/utils/get-project-graph-from-gradle-plugin';
|
||||
import { join } from 'path';
|
||||
|
||||
let gradleReport: GradleReport;
|
||||
jest.mock('./src/utils/get-gradle-report', () => {
|
||||
let gradleReport: ProjectGraphReport;
|
||||
jest.mock('./src/plugin/utils/get-project-graph-from-gradle-plugin', () => {
|
||||
return {
|
||||
GRADLE_BUILD_FILES: new Set(['build.gradle', 'build.gradle.kts']),
|
||||
populateGradleReport: jest.fn().mockImplementation(() => void 0),
|
||||
getCurrentGradleReport: jest.fn().mockImplementation(() => gradleReport),
|
||||
populateProjectGraph: jest.fn().mockImplementation(() => void 0),
|
||||
getCurrentProjectGraphReport: jest
|
||||
.fn()
|
||||
.mockImplementation(() => gradleReport),
|
||||
};
|
||||
});
|
||||
|
||||
@ -19,26 +22,9 @@ describe('@nx/gradle/plugin', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
tempFs = new TempFs('gradle-plugin');
|
||||
gradleReport = {
|
||||
gradleFileToGradleProjectMap: new Map<string, string>([
|
||||
['proj/build.gradle', 'proj'],
|
||||
]),
|
||||
buildFileToDepsMap: new Map<string, Set<string>>(),
|
||||
gradleFileToOutputDirsMap: new Map<string, Map<string, string>>([
|
||||
['proj/build.gradle', new Map([['build', 'build']])],
|
||||
]),
|
||||
gradleProjectToTasksMap: new Map<string, Set<string>>([
|
||||
['proj', new Set(['test'])],
|
||||
]),
|
||||
gradleProjectToTasksTypeMap: new Map<string, Map<string, string>>([
|
||||
['proj', new Map([['test', 'Verification']])],
|
||||
]),
|
||||
gradleProjectToProjectName: new Map<string, string>([['proj', 'proj']]),
|
||||
gradleProjectNameToProjectRootMap: new Map<string, string>([
|
||||
['proj', 'proj'],
|
||||
]),
|
||||
gradleProjectToChildProjects: new Map<string, string[]>(),
|
||||
};
|
||||
gradleReport = readJsonFile(
|
||||
join(__dirname, 'src/plugin/utils/__mocks__/gradle_tutorial.json')
|
||||
);
|
||||
context = {
|
||||
nxJsonConfiguration: {
|
||||
namedInputs: {
|
||||
@ -76,48 +62,33 @@ describe('@nx/gradle/plugin', () => {
|
||||
[
|
||||
"proj/build.gradle",
|
||||
{
|
||||
"externalNodes": {},
|
||||
"projects": {
|
||||
"proj": {
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"Verification": [
|
||||
"test",
|
||||
"help": [
|
||||
"buildEnvironment",
|
||||
],
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"name": "proj",
|
||||
"projectType": "application",
|
||||
"name": "gradle-tutorial",
|
||||
"root": "proj",
|
||||
"targets": {
|
||||
"test": {
|
||||
"buildEnvironment": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:test",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"command": "./gradlew :buildEnvironment",
|
||||
"metadata": {
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"description": "Displays all buildscript dependencies declared in root project 'gradle-tutorial'.",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
"cwd": "proj",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
export { createDependencies } from './src/plugin/dependencies';
|
||||
export { createNodes, createNodesV2 } from './src/plugin/nodes';
|
||||
export { createNodesV2 } from './src/plugin/nodes';
|
||||
|
||||
3
packages/gradle/project-graph/.gitignore
vendored
Normal file
3
packages/gradle/project-graph/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Ignore Gradle project-specific cache directory
|
||||
bin
|
||||
build
|
||||
56
packages/gradle/project-graph/README.md
Normal file
56
packages/gradle/project-graph/README.md
Normal file
@ -0,0 +1,56 @@
|
||||
# dev.nx.gradle.project-graph
|
||||
|
||||
This gradle plugin contains
|
||||
|
||||
## Installation
|
||||
|
||||
Kotlin
|
||||
build.gradle.kts
|
||||
|
||||
```
|
||||
plugins {
|
||||
id("dev.nx.gradle.project-graph") version("+")
|
||||
}
|
||||
```
|
||||
|
||||
Groovy
|
||||
build.gradle
|
||||
|
||||
```
|
||||
plugins {
|
||||
id "dev.nx.gradle.project-graph" version "+"
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
./gradlew nxProjectGraph
|
||||
```
|
||||
|
||||
In terminal, it should output something like:
|
||||
|
||||
```
|
||||
> Task :nxProjectGraph
|
||||
< your workspace >/build/nx/add-nx-to-gradle.json
|
||||
```
|
||||
|
||||
To pass in a hash parameter:
|
||||
|
||||
```bash
|
||||
./gradlew nxProjectGraph -Phash=12345
|
||||
```
|
||||
|
||||
It generates a json file to be consumed by nx:
|
||||
|
||||
```json
|
||||
{
|
||||
"nodes": {
|
||||
"app": {
|
||||
"targets": {}
|
||||
}
|
||||
},
|
||||
"dependencies": [],
|
||||
"externalNodes": {}
|
||||
}
|
||||
```
|
||||
120
packages/gradle/project-graph/build.gradle.kts
Normal file
120
packages/gradle/project-graph/build.gradle.kts
Normal file
@ -0,0 +1,120 @@
|
||||
plugins {
|
||||
`java-gradle-plugin`
|
||||
`maven-publish`
|
||||
signing
|
||||
id("com.ncorti.ktfmt.gradle") version "+"
|
||||
id("dev.nx.gradle.project-graph") version "0.0.2"
|
||||
id("org.jetbrains.kotlin.jvm") version "2.1.10"
|
||||
id("com.gradle.plugin-publish") version "1.2.1"
|
||||
}
|
||||
|
||||
group = "dev.nx.gradle"
|
||||
|
||||
version = "0.0.2"
|
||||
|
||||
repositories { mavenCentral() }
|
||||
|
||||
dependencies {
|
||||
implementation("com.google.code.gson:gson:2.10.1")
|
||||
testImplementation(kotlin("test"))
|
||||
testImplementation("org.mockito:mockito-core:5.8.0")
|
||||
testImplementation("org.mockito.kotlin:mockito-kotlin:5.2.1")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.10.1")
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
website = "https://nx.dev/"
|
||||
vcsUrl = "https://github.com/nrwl/nx"
|
||||
plugins {
|
||||
create("nxProjectGraphPlugin") {
|
||||
id = "dev.nx.gradle.project-graph"
|
||||
implementationClass = "dev.nx.gradle.NxProjectGraphReportPlugin"
|
||||
displayName = "The Nx Plugin for Gradle to generate Nx project graph"
|
||||
description = "Generates a JSON file with nodes, dependencies, and external nodes for Nx"
|
||||
tags = listOf("nx", "monorepo", "javascript", "typescript")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
publishing {
|
||||
publications.named("pluginMaven", MavenPublication::class) {
|
||||
pom {
|
||||
name.set("Nx Gradle Project Graph Plugin")
|
||||
description.set(
|
||||
"A plugin to generate a JSON file with nodes, dependencies, and external nodes for Nx")
|
||||
url.set("https://github.com/nrwl/nx")
|
||||
|
||||
licenses { license { name.set("MIT") } }
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id.set("nx")
|
||||
name.set("Nx")
|
||||
email.set("java-services@nrwl.io")
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
connection.set("scm:git:git://github.com/nrwl/nx.git")
|
||||
developerConnection.set("scm:git:ssh://github.com/nrwl/nx.git")
|
||||
url.set("https://github.com/nrwl/nx")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name = "localStaging"
|
||||
url = uri(layout.buildDirectory.dir("staging"))
|
||||
}
|
||||
}
|
||||
}
|
||||
publishing {
|
||||
publications.named("nxProjectGraphPluginPluginMarkerMaven", MavenPublication::class) {
|
||||
pom {
|
||||
name.set("Nx Gradle Project Graph Plugin")
|
||||
description.set(
|
||||
"A plugin to generate a JSON file with nodes, dependencies, and external nodes for Nx")
|
||||
url.set("https://github.com/nrwl/nx")
|
||||
|
||||
licenses { license { name.set("MIT") } }
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id.set("nx")
|
||||
name.set("Nx")
|
||||
email.set("java-services@nrwl.io")
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
connection.set("scm:git:git://github.com/nrwl/nx.git")
|
||||
developerConnection.set("scm:git:ssh://github.com/nrwl/nx.git")
|
||||
url.set("https://github.com/nrwl/nx")
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name = "localStaging"
|
||||
url = uri(layout.buildDirectory.dir("staging"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
afterEvaluate {
|
||||
sign(publishing.publications["pluginMaven"])
|
||||
sign(publishing.publications["nxProjectGraphPluginPluginMarkerMaven"])
|
||||
}
|
||||
}
|
||||
|
||||
tasks.test { useJUnitPlatform() }
|
||||
43
packages/gradle/project-graph/project.json
Normal file
43
packages/gradle/project-graph/project.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "gradle-project-graph",
|
||||
"$schema": "node_modules/nx/schemas/project-schema.json",
|
||||
"targets": {
|
||||
"test": {
|
||||
"command": "./gradlew :project-graph:test",
|
||||
"options": {
|
||||
"args": []
|
||||
},
|
||||
"cache": true
|
||||
},
|
||||
"lint": {
|
||||
"command": "./gradlew :project-graph:ktfmtCheck",
|
||||
"cache": true
|
||||
},
|
||||
"format": {
|
||||
"command": "./gradlew :project-graph:ktfmtFormat",
|
||||
"cache": true
|
||||
},
|
||||
"publish-staging": {
|
||||
"command": "./gradlew :project-graph:publish",
|
||||
"cache": true,
|
||||
"outputs": ["{projectRoot}/build/staging"]
|
||||
},
|
||||
"zip-staging": {
|
||||
"command": "zip -r ../deployment.zip .",
|
||||
"options": {
|
||||
"cwd": "{projectRoot}/build/staging"
|
||||
},
|
||||
"inputs": ["{projectRoot}/build/staging"],
|
||||
"outputs": ["{projectRoot}/build/deployment.zip"],
|
||||
"dependsOn": ["publish-staging"]
|
||||
},
|
||||
"maven": {
|
||||
"command": "npx ts-node publish-maven.ts --deploymentZipPath=build/deployment.zip",
|
||||
"options": {
|
||||
"cwd": "{projectRoot}"
|
||||
},
|
||||
"inputs": ["{projectRoot}/build/deployment.zip"],
|
||||
"dependsOn": ["zip-staging"]
|
||||
}
|
||||
}
|
||||
}
|
||||
133
packages/gradle/project-graph/publish-maven.ts
Normal file
133
packages/gradle/project-graph/publish-maven.ts
Normal file
@ -0,0 +1,133 @@
|
||||
import axios from 'axios';
|
||||
import * as fs from 'fs';
|
||||
import * as FormData from 'form-data';
|
||||
|
||||
function parseArgs() {
|
||||
const args = process.argv.slice(2);
|
||||
const result: Record<string, string> = {};
|
||||
args.forEach((arg) => {
|
||||
const [key, value] = arg.replace(/^--/, '').split('=');
|
||||
result[key] = value;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
async function publishToMavenApi(
|
||||
username: string,
|
||||
password: string,
|
||||
deploymentZipPath = 'deployment.zip'
|
||||
) {
|
||||
const token = Buffer.from(`${username}:${password}`).toString('base64');
|
||||
console.log(`📦 Publishing to Maven Central...`);
|
||||
|
||||
const url = 'https://central.sonatype.com/api/v1/publisher/upload';
|
||||
const form = new FormData();
|
||||
form.append('bundle', fs.createReadStream(deploymentZipPath));
|
||||
|
||||
let uploadId: string;
|
||||
try {
|
||||
const response = await axios.post(url, form, {
|
||||
headers: {
|
||||
Authorization: `Basic ${token}`,
|
||||
...form.getHeaders(),
|
||||
},
|
||||
});
|
||||
uploadId = response.data.toString().trim();
|
||||
console.log(`✅ Upload ID: ${uploadId}`);
|
||||
} catch (err: any) {
|
||||
console.error('🚫 Upload failed:', err.response?.data || err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let currentStatus = await getUploadStatus(uploadId, token);
|
||||
if (['PENDING', 'VALIDATING', 'PUBLISHING'].includes(currentStatus)) {
|
||||
currentStatus = await retryUntilValidatedOrPublished(
|
||||
currentStatus,
|
||||
uploadId,
|
||||
token
|
||||
);
|
||||
}
|
||||
|
||||
if (!['VALIDATED', 'PUBLISHED'].includes(currentStatus)) {
|
||||
console.error(`🚫 Upload failed with final status: ${currentStatus}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`📦 Upload is ${currentStatus}, proceeding to deploy...`);
|
||||
if (currentStatus === 'PUBLISHED') {
|
||||
console.log('✅ Already published, skipping deployment.');
|
||||
return;
|
||||
}
|
||||
|
||||
const deployUrl = `https://central.sonatype.com/api/v1/publisher/deployment/${uploadId}`;
|
||||
try {
|
||||
const deployRes = await axios.post(deployUrl, null, {
|
||||
headers: { Authorization: `Basic ${token}` },
|
||||
});
|
||||
console.log(`🚀 Deployment response: ${deployRes.data}`);
|
||||
} catch (err: any) {
|
||||
console.error('🚫 Deployment failed:', err.response?.data || err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
async function getUploadStatus(
|
||||
uploadId: string,
|
||||
token: string
|
||||
): Promise<string> {
|
||||
const url = `https://central.sonatype.com/api/v1/publisher/status?id=${uploadId}`;
|
||||
try {
|
||||
const response = await axios.post(url, null, {
|
||||
headers: { Authorization: `Basic ${token}` },
|
||||
});
|
||||
const state = response.data.deploymentState;
|
||||
console.log(`📡 Current deployment state: ${state}`);
|
||||
return state;
|
||||
} catch (err: any) {
|
||||
console.error(
|
||||
'🚫 Failed to get status:',
|
||||
err.response?.data || err.message
|
||||
);
|
||||
return 'FAILED';
|
||||
}
|
||||
}
|
||||
|
||||
async function retryUntilValidatedOrPublished(
|
||||
currentStatus: string,
|
||||
uploadId: string,
|
||||
token: string,
|
||||
retries = 10,
|
||||
delay = 10_000
|
||||
): Promise<string> {
|
||||
for (let i = 0; i < retries; i++) {
|
||||
console.log(`🔁 Checking status (attempt ${i + 1}/${retries})...`);
|
||||
await sleep(delay);
|
||||
currentStatus = await getUploadStatus(uploadId, token);
|
||||
if (['VALIDATED', 'PUBLISHED', 'FAILED'].includes(currentStatus)) break;
|
||||
}
|
||||
return currentStatus;
|
||||
}
|
||||
|
||||
function sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
// Entry
|
||||
(async function main() {
|
||||
let { username, password, deploymentZipPath } = parseArgs();
|
||||
|
||||
username = username || process.env.MAVEN_USERNAME;
|
||||
password = password || process.env.MAVEN_PASSWORD;
|
||||
|
||||
if (!username || !password) {
|
||||
console.error('❌ Missing MAVEN_USERNAME or MAVEN_PASSWORD');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!deploymentZipPath) {
|
||||
console.error('❌ Missing required --deploymentZipPath argument');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await publishToMavenApi(username, password, deploymentZipPath);
|
||||
})();
|
||||
16
packages/gradle/project-graph/settings.gradle.kts
Normal file
16
packages/gradle/project-graph/settings.gradle.kts
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* The settings file is used to specify which projects to include in your build.
|
||||
* For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.5/userguide/building_swift_projects.html in the Gradle documentation.
|
||||
*/
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "project-graph"
|
||||
@ -0,0 +1,94 @@
|
||||
package dev.nx.gradle
|
||||
|
||||
import java.util.*
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
|
||||
class NxProjectGraphReportPlugin : Plugin<Project> {
|
||||
override fun apply(project: Project) {
|
||||
project.logger.info("${Date()} Applying NxProjectGraphReportPlugin to ${project.name}")
|
||||
|
||||
val nxProjectReportTask: TaskProvider<NxProjectReportTask> =
|
||||
project.tasks.register("nxProjectReport", NxProjectReportTask::class.java) { task ->
|
||||
val hashProperty =
|
||||
project.findProperty("hash")?.toString()
|
||||
?: run {
|
||||
project.logger.warn(
|
||||
"No 'hash' property was provided for $project. Using default hash value: 'default-hash'")
|
||||
"default-hash"
|
||||
}
|
||||
|
||||
val cwdProperty =
|
||||
project.findProperty("cwd")?.toString()
|
||||
?: run {
|
||||
project.logger.warn(
|
||||
"No 'cwd' property was provided for $project. Using default hash value: ${System.getProperty("user.dir")}")
|
||||
System.getProperty("user.dir")
|
||||
}
|
||||
|
||||
val workspaceRootProperty =
|
||||
project.findProperty("workspaceRoot")?.toString()
|
||||
?: run {
|
||||
project.logger.warn(
|
||||
"No 'workspaceRoot' property was provided for $project. Using default hash value: ${System.getProperty("user.dir")}")
|
||||
System.getProperty("user.dir")
|
||||
}
|
||||
|
||||
val targetNameOverrides: Map<String, String> =
|
||||
project.properties
|
||||
.filterKeys { it.endsWith("TargetName") }
|
||||
.mapValues { it.value.toString() }
|
||||
task.projectName.set(project.name)
|
||||
task.projectRef.set(project)
|
||||
task.hash.set(hashProperty)
|
||||
task.targetNameOverrides.set(targetNameOverrides)
|
||||
task.cwd.set(cwdProperty)
|
||||
task.workspaceRoot.set(workspaceRootProperty)
|
||||
|
||||
task.description = "Create Nx project report for ${project.name}"
|
||||
task.group = "Reporting"
|
||||
|
||||
task.doFirst { it.logger.info("${Date()} Running nxProjectReport for ${project.name}") }
|
||||
}
|
||||
|
||||
// Ensure all included builds are processed only once using lazy evaluation
|
||||
project.gradle.includedBuilds.distinct().forEach { includedBuild ->
|
||||
nxProjectReportTask.configure { it.dependsOn(includedBuild.task(":nxProjectReport")) }
|
||||
}
|
||||
|
||||
// Ensure all subprojects are processed only once using lazy evaluation
|
||||
project.subprojects.distinct().forEach { subProject ->
|
||||
// Add a dependency on each subproject's nxProjectReport task
|
||||
nxProjectReportTask.configure {
|
||||
it.dependsOn(subProject.tasks.matching { it.name == "nxProjectReport" })
|
||||
}
|
||||
}
|
||||
|
||||
project.tasks.register("nxProjectGraph").configure { task ->
|
||||
task.dependsOn(nxProjectReportTask)
|
||||
task.description = "Create Nx project graph for ${project.name}"
|
||||
task.group = "Reporting"
|
||||
|
||||
val outputFileProvider = nxProjectReportTask.map { it.outputFile }
|
||||
|
||||
task.doFirst { it.logger.info("${Date()} Running nxProjectGraph for ${project.name}") }
|
||||
|
||||
task.doLast { println(outputFileProvider.get().path) }
|
||||
}
|
||||
|
||||
// Ensure all included builds are processed only once using lazy evaluation
|
||||
project.gradle.includedBuilds.distinct().forEach { includedBuild ->
|
||||
project.tasks.named("nxProjectGraph").configure {
|
||||
it.dependsOn(includedBuild.task(":nxProjectGraph"))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure all subprojects are processed only once using lazy evaluation
|
||||
project.subprojects.distinct().forEach { subProject ->
|
||||
project.tasks.named("nxProjectGraph").configure {
|
||||
it.dependsOn(subProject.tasks.matching { it.name == "nxProjectGraph" })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
package dev.nx.gradle
|
||||
|
||||
import com.google.gson.Gson
|
||||
import dev.nx.gradle.utils.createNodeForProject
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.ProjectLayout
|
||||
import org.gradle.api.provider.MapProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
|
||||
@CacheableTask
|
||||
abstract class NxProjectReportTask @Inject constructor(private val projectLayout: ProjectLayout) :
|
||||
DefaultTask() {
|
||||
|
||||
companion object {
|
||||
private val gson = Gson()
|
||||
}
|
||||
|
||||
@get:Input abstract val projectName: Property<String>
|
||||
|
||||
@get:Input abstract val hash: Property<String>
|
||||
|
||||
@get:Input abstract val cwd: Property<String>
|
||||
|
||||
@get:Input abstract val workspaceRoot: Property<String>
|
||||
|
||||
@get:Input abstract val targetNameOverrides: MapProperty<String, String>
|
||||
|
||||
// Don't compute report at configuration time, move it to execution time
|
||||
@get:Internal // Prevent Gradle from caching this reference
|
||||
abstract val projectRef: Property<Project>
|
||||
|
||||
@get:OutputFile
|
||||
val outputFile: File
|
||||
get() = projectLayout.buildDirectory.file("nx/${projectName.get()}.json").get().asFile
|
||||
|
||||
@TaskAction
|
||||
fun action() {
|
||||
logger.info("${Date()} Apply task action NxProjectReportTask for ${projectName.get()}")
|
||||
logger.info("${Date()} Hash input: ${hash.get()}")
|
||||
logger.info("${Date()} Target Name Overrides ${targetNameOverrides.get()}")
|
||||
val project = projectRef.get() // Get project reference at execution time
|
||||
val report =
|
||||
createNodeForProject(
|
||||
project,
|
||||
targetNameOverrides.get(),
|
||||
workspaceRoot.get(),
|
||||
cwd.get()) // Compute report at execution time
|
||||
val reportJson = gson.toJson(report)
|
||||
|
||||
if (outputFile.exists() && outputFile.readText() == reportJson) {
|
||||
logger.info("${Date()} No change in the node report for ${projectName.get()}")
|
||||
return
|
||||
}
|
||||
|
||||
logger.info("${Date()} Writing node report for ${projectName.get()}")
|
||||
outputFile.writeText(reportJson)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
package dev.nx.gradle.data
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class Dependency(val source: String, val target: String, var sourceFile: String) :
|
||||
Serializable
|
||||
@ -0,0 +1,10 @@
|
||||
package dev.nx.gradle.data
|
||||
|
||||
import java.io.Serializable
|
||||
import org.gradle.api.tasks.Input
|
||||
|
||||
data class ExternalDepData(
|
||||
@Input val version: String?,
|
||||
@Input val packageName: String,
|
||||
@Input val hash: String?
|
||||
) : Serializable
|
||||
@ -0,0 +1,11 @@
|
||||
package dev.nx.gradle.data
|
||||
|
||||
import java.io.Serializable
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Nested
|
||||
|
||||
data class ExternalNode(
|
||||
@Input var type: String?,
|
||||
@Input val name: String,
|
||||
@Nested var data: ExternalDepData
|
||||
) : Serializable
|
||||
@ -0,0 +1,11 @@
|
||||
package dev.nx.gradle.data
|
||||
|
||||
import java.io.Serializable
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Nested
|
||||
|
||||
data class GradleNodeReport(
|
||||
@Nested val nodes: Map<String, ProjectNode>,
|
||||
@Input val dependencies: Set<Dependency>,
|
||||
@Nested val externalNodes: Map<String, ExternalNode>
|
||||
) : Serializable
|
||||
@ -0,0 +1,17 @@
|
||||
package dev.nx.gradle.data
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
typealias NxTarget = MutableMap<String, Any?>
|
||||
|
||||
typealias NxTargets = MutableMap<String, NxTarget>
|
||||
|
||||
typealias TargetGroup = MutableList<String>
|
||||
|
||||
typealias TargetGroups = MutableMap<String, TargetGroup>
|
||||
|
||||
data class GradleTargets(
|
||||
val targets: NxTargets,
|
||||
val targetGroups: TargetGroups,
|
||||
var externalNodes: MutableMap<String, ExternalNode>
|
||||
) : Serializable
|
||||
@ -0,0 +1,9 @@
|
||||
package dev.nx.gradle.data
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class NodeMetadata(
|
||||
val targetGroups: TargetGroups,
|
||||
val technologies: List<String>,
|
||||
val description: String?
|
||||
) : Serializable
|
||||
@ -0,0 +1,10 @@
|
||||
package dev.nx.gradle.data
|
||||
|
||||
import java.io.Serializable
|
||||
import org.gradle.api.tasks.Input
|
||||
|
||||
data class ProjectNode(
|
||||
@Input val targets: NxTargets,
|
||||
@Input val metadata: NodeMetadata,
|
||||
@Input val name: String
|
||||
) : Serializable
|
||||
@ -0,0 +1,143 @@
|
||||
package dev.nx.gradle.utils
|
||||
|
||||
import dev.nx.gradle.data.*
|
||||
import java.io.File
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.file.FileCollection
|
||||
|
||||
const val testCiTargetGroup = "verification"
|
||||
|
||||
/**
|
||||
* Add atomized ci test targets Going to loop through each test files and create a target for each
|
||||
* It is going to modify targets and targetGroups in place
|
||||
*/
|
||||
fun addTestCiTargets(
|
||||
testFiles: FileCollection,
|
||||
projectBuildPath: String,
|
||||
testTask: Task,
|
||||
targets: NxTargets,
|
||||
targetGroups: TargetGroups,
|
||||
projectRoot: String,
|
||||
workspaceRoot: String,
|
||||
ciTargetName: String
|
||||
) {
|
||||
ensureTargetGroupExists(targetGroups, testCiTargetGroup)
|
||||
|
||||
val gradlewCommand = getGradlewCommand()
|
||||
val ciDependsOn = mutableListOf<Map<String, String>>()
|
||||
|
||||
val filteredTestFiles = testFiles.filter { isTestFile(it, workspaceRoot) }
|
||||
|
||||
filteredTestFiles.forEach { testFile ->
|
||||
val className = getTestClassNameIfAnnotated(testFile) ?: return@forEach
|
||||
|
||||
val testCiTarget =
|
||||
buildTestCiTarget(
|
||||
gradlewCommand = gradlewCommand,
|
||||
projectBuildPath = projectBuildPath,
|
||||
testClassName = className,
|
||||
testFile = testFile,
|
||||
testTask = testTask,
|
||||
projectRoot = projectRoot,
|
||||
workspaceRoot = workspaceRoot)
|
||||
|
||||
val targetName = "$ciTargetName--$className"
|
||||
targets[targetName] = testCiTarget
|
||||
targetGroups[testCiTargetGroup]?.add(targetName)
|
||||
|
||||
ciDependsOn.add(mapOf("target" to targetName, "projects" to "self", "params" to "forward"))
|
||||
}
|
||||
|
||||
testTask.logger.info("$testTask ci tasks: $ciDependsOn")
|
||||
|
||||
if (ciDependsOn.isNotEmpty()) {
|
||||
ensureParentCiTarget(
|
||||
targets = targets,
|
||||
targetGroups = targetGroups,
|
||||
ciTargetName = ciTargetName,
|
||||
projectBuildPath = projectBuildPath,
|
||||
dependsOn = ciDependsOn)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTestClassNameIfAnnotated(file: File): String? {
|
||||
if (!file.exists()) return null
|
||||
|
||||
val content = file.readText()
|
||||
if (!content.contains("@Test")) return null
|
||||
|
||||
val classRegex = Regex("""class\s+([A-Za-z_][A-Za-z0-9_]*)""")
|
||||
val match = classRegex.find(content)
|
||||
return match?.groupValues?.get(1)
|
||||
}
|
||||
|
||||
fun ensureTargetGroupExists(targetGroups: TargetGroups, group: String) {
|
||||
if (!targetGroups.containsKey(group)) {
|
||||
targetGroups[group] = mutableListOf()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isTestFile(file: File, workspaceRoot: String): Boolean {
|
||||
val fileName = file.name.substringBefore(".")
|
||||
val regex = "^(?!abstract).*?(Test)(s)?\\d*".toRegex(RegexOption.IGNORE_CASE)
|
||||
return file.path.startsWith(workspaceRoot) && regex.matches(fileName)
|
||||
}
|
||||
|
||||
private fun buildTestCiTarget(
|
||||
gradlewCommand: String,
|
||||
projectBuildPath: String,
|
||||
testClassName: String,
|
||||
testFile: File,
|
||||
testTask: Task,
|
||||
projectRoot: String,
|
||||
workspaceRoot: String
|
||||
): MutableMap<String, Any?> {
|
||||
val target =
|
||||
mutableMapOf<String, Any?>(
|
||||
"command" to "$gradlewCommand ${projectBuildPath}:test --tests $testClassName",
|
||||
"metadata" to
|
||||
getMetadata("Runs Gradle test $testClassName in CI", projectBuildPath, "test"),
|
||||
"cache" to true,
|
||||
"inputs" to arrayOf(replaceRootInPath(testFile.path, projectRoot, workspaceRoot)))
|
||||
|
||||
getDependsOnForTask(testTask, null)
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
?.let {
|
||||
testTask.logger.info("$testTask: processed ${it.size} dependsOn")
|
||||
target["dependsOn"] = it
|
||||
}
|
||||
|
||||
getOutputsForTask(testTask, projectRoot, workspaceRoot)
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
?.let {
|
||||
testTask.logger.info("$testTask: processed ${it.size} outputs")
|
||||
target["outputs"] = it
|
||||
}
|
||||
|
||||
return target
|
||||
}
|
||||
|
||||
private fun ensureParentCiTarget(
|
||||
targets: NxTargets,
|
||||
targetGroups: TargetGroups,
|
||||
ciTargetName: String,
|
||||
projectBuildPath: String,
|
||||
dependsOn: List<Map<String, String>>
|
||||
) {
|
||||
val ciTarget =
|
||||
targets.getOrPut(ciTargetName) {
|
||||
mutableMapOf<String, Any?>().apply {
|
||||
put("executor", "nx:noop")
|
||||
put("metadata", getMetadata("Runs Gradle Tests in CI", projectBuildPath, "test", "test"))
|
||||
put("dependsOn", mutableListOf<Map<String, String>>())
|
||||
put("cache", true)
|
||||
}
|
||||
}
|
||||
|
||||
val dependsOnList = ciTarget.getOrPut("dependsOn") { mutableListOf<Any?>() } as MutableList<Any?>
|
||||
dependsOnList.addAll(dependsOn)
|
||||
|
||||
if (targetGroups[testCiTargetGroup]?.contains(ciTargetName) != true) {
|
||||
targetGroups[testCiTargetGroup]?.add(ciTargetName)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,159 @@
|
||||
package dev.nx.gradle.utils
|
||||
|
||||
import dev.nx.gradle.data.*
|
||||
import java.util.*
|
||||
import org.gradle.api.Project
|
||||
|
||||
/** Loops through a project and populate dependencies and nodes for each target */
|
||||
fun createNodeForProject(
|
||||
project: Project,
|
||||
targetNameOverrides: Map<String, String>,
|
||||
workspaceRoot: String,
|
||||
cwd: String
|
||||
): GradleNodeReport {
|
||||
val logger = project.logger
|
||||
logger.info("${Date()} ${project.name} createNodeForProject: get nodes and dependencies")
|
||||
|
||||
// Initialize dependencies with an empty Set to prevent null issues
|
||||
val dependencies: MutableSet<Dependency> =
|
||||
try {
|
||||
getDependenciesForProject(project)
|
||||
} catch (e: Exception) {
|
||||
logger.info(
|
||||
"${Date()} ${project.name} createNodeForProject: get dependencies error: ${e.message}")
|
||||
mutableSetOf()
|
||||
}
|
||||
logger.info("${Date()} ${project.name} createNodeForProject: got dependencies")
|
||||
|
||||
// Initialize nodes and externalNodes with empty maps to prevent null issues
|
||||
var nodes: Map<String, ProjectNode>
|
||||
var externalNodes: Map<String, ExternalNode>
|
||||
|
||||
try {
|
||||
val gradleTargets: GradleTargets =
|
||||
processTargetsForProject(project, dependencies, targetNameOverrides, workspaceRoot, cwd)
|
||||
val projectRoot = project.projectDir.path
|
||||
val projectNode =
|
||||
ProjectNode(
|
||||
targets = gradleTargets.targets,
|
||||
metadata =
|
||||
NodeMetadata(gradleTargets.targetGroups, listOf("gradle"), project.description),
|
||||
name = project.name)
|
||||
nodes = mapOf(projectRoot to projectNode)
|
||||
externalNodes = gradleTargets.externalNodes
|
||||
logger.info(
|
||||
"${Date()} ${project.name} createNodeForProject: get nodes and external nodes for $projectRoot")
|
||||
} catch (e: Exception) {
|
||||
logger.info("${project.name}: get nodes error: ${e.message}")
|
||||
nodes = emptyMap()
|
||||
externalNodes = emptyMap()
|
||||
}
|
||||
return GradleNodeReport(nodes, dependencies, externalNodes)
|
||||
}
|
||||
|
||||
/**
|
||||
* Process targets for project
|
||||
*
|
||||
* @return targets and targetGroups
|
||||
*/
|
||||
fun processTargetsForProject(
|
||||
project: Project,
|
||||
dependencies: MutableSet<Dependency>,
|
||||
targetNameOverrides: Map<String, String>,
|
||||
workspaceRoot: String,
|
||||
cwd: String
|
||||
): GradleTargets {
|
||||
val targets: NxTargets = mutableMapOf<String, MutableMap<String, Any?>>()
|
||||
val targetGroups: TargetGroups = mutableMapOf<String, MutableList<String>>()
|
||||
val externalNodes = mutableMapOf<String, ExternalNode>()
|
||||
val projectRoot = project.projectDir.path
|
||||
project.logger.info("Using workspace root $workspaceRoot")
|
||||
|
||||
var projectBuildPath: String =
|
||||
project
|
||||
.buildTreePath // get the build path of project e.g. :app, :utils:number-utils, :buildSrc
|
||||
if (projectBuildPath.endsWith(":")) { // root project is ":", manually remove last :
|
||||
projectBuildPath = projectBuildPath.dropLast(1)
|
||||
}
|
||||
|
||||
val logger = project.logger
|
||||
|
||||
logger.info("${Date()} ${project}: process targets")
|
||||
|
||||
var gradleProject = project.buildTreePath
|
||||
if (!gradleProject.endsWith(":")) {
|
||||
gradleProject += ":"
|
||||
}
|
||||
|
||||
project.tasks.forEach { task ->
|
||||
try {
|
||||
logger.info("${Date()} ${project.name}: Processing $task")
|
||||
val taskName = targetNameOverrides.getOrDefault(task.name + "TargetName", task.name)
|
||||
// add task to target groups
|
||||
val group: String? = task.group
|
||||
if (!group.isNullOrBlank()) {
|
||||
if (targetGroups.contains(group)) {
|
||||
targetGroups[group]?.add(task.name)
|
||||
} else {
|
||||
targetGroups[group] = mutableListOf(task.name)
|
||||
}
|
||||
}
|
||||
|
||||
val target =
|
||||
processTask(
|
||||
task,
|
||||
projectBuildPath,
|
||||
projectRoot,
|
||||
workspaceRoot,
|
||||
cwd,
|
||||
externalNodes,
|
||||
dependencies,
|
||||
targetNameOverrides)
|
||||
targets[taskName] = target
|
||||
|
||||
val ciTargetName = targetNameOverrides.getOrDefault("ciTargetName", null)
|
||||
ciTargetName?.let {
|
||||
if (task.name.startsWith("compileTest")) {
|
||||
val testTask = project.getTasksByName("test", false)
|
||||
if (testTask.isNotEmpty()) {
|
||||
addTestCiTargets(
|
||||
task.inputs.sourceFiles,
|
||||
projectBuildPath,
|
||||
testTask.first(),
|
||||
targets,
|
||||
targetGroups,
|
||||
projectRoot,
|
||||
workspaceRoot,
|
||||
it)
|
||||
}
|
||||
}
|
||||
|
||||
// Add the `$ciTargetName-check` target when processing the "check" task
|
||||
if (task.name == "check") {
|
||||
val replacedDependencies =
|
||||
(target["dependsOn"] as? List<*>)?.map { dep ->
|
||||
if (dep.toString() == targetNameOverrides.getOrDefault("testTargetName", "test"))
|
||||
ciTargetName
|
||||
else dep.toString()
|
||||
} ?: emptyList()
|
||||
|
||||
// Copy the original target and override "dependsOn"
|
||||
val newTarget = target.toMutableMap()
|
||||
newTarget["dependsOn"] = replacedDependencies
|
||||
|
||||
val ciCheckTargetName = "$ciTargetName-check"
|
||||
targets[ciCheckTargetName] = newTarget
|
||||
|
||||
ensureTargetGroupExists(targetGroups, testCiTargetGroup)
|
||||
targetGroups[testCiTargetGroup]?.add(ciCheckTargetName)
|
||||
}
|
||||
}
|
||||
logger.info("${Date()} ${project.name}: Processed $task")
|
||||
} catch (e: Exception) {
|
||||
logger.info("${task}: process task error $e")
|
||||
logger.debug("Stack trace:", e)
|
||||
}
|
||||
}
|
||||
|
||||
return GradleTargets(targets, targetGroups, externalNodes)
|
||||
}
|
||||
@ -0,0 +1,348 @@
|
||||
package dev.nx.gradle.utils
|
||||
|
||||
import dev.nx.gradle.data.*
|
||||
import org.gradle.api.Named
|
||||
import org.gradle.api.NamedDomainObjectProvider
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
|
||||
/**
|
||||
* Process a task and convert it into target Going to populate:
|
||||
* - cache
|
||||
* - inputs
|
||||
* - outputs
|
||||
* - command
|
||||
* - metadata
|
||||
* - options with cwd and args
|
||||
*/
|
||||
fun processTask(
|
||||
task: Task,
|
||||
projectBuildPath: String,
|
||||
projectRoot: String,
|
||||
workspaceRoot: String,
|
||||
cwd: String,
|
||||
externalNodes: MutableMap<String, ExternalNode>,
|
||||
dependencies: MutableSet<Dependency>,
|
||||
targetNameOverrides: Map<String, String>
|
||||
): MutableMap<String, Any?> {
|
||||
val logger = task.logger
|
||||
logger.info("NxProjectReportTask: process $task for $projectRoot")
|
||||
val target = mutableMapOf<String, Any?>()
|
||||
target["cache"] = true // set cache to be always true
|
||||
|
||||
// process inputs
|
||||
val inputs = getInputsForTask(task, projectRoot, workspaceRoot, externalNodes)
|
||||
if (!inputs.isNullOrEmpty()) {
|
||||
logger.info("${task}: processed ${inputs.size} inputs")
|
||||
target["inputs"] = inputs
|
||||
}
|
||||
|
||||
// process outputs
|
||||
val outputs = getOutputsForTask(task, projectRoot, workspaceRoot)
|
||||
if (!outputs.isNullOrEmpty()) {
|
||||
logger.info("${task}: processed ${outputs.size} outputs")
|
||||
target["outputs"] = outputs
|
||||
}
|
||||
|
||||
// process dependsOn
|
||||
val dependsOn = getDependsOnForTask(task, dependencies, targetNameOverrides)
|
||||
if (!dependsOn.isNullOrEmpty()) {
|
||||
logger.info("${task}: processed ${dependsOn.size} dependsOn")
|
||||
target["dependsOn"] = dependsOn
|
||||
}
|
||||
|
||||
val gradlewCommand = getGradlewCommand()
|
||||
target["command"] = "$gradlewCommand ${projectBuildPath}:${task.name}"
|
||||
|
||||
val metadata = getMetadata(task.description ?: "Run ${task.name}", projectBuildPath, task.name)
|
||||
target["metadata"] = metadata
|
||||
|
||||
target["options"] = mapOf("cwd" to cwd)
|
||||
|
||||
return target
|
||||
}
|
||||
|
||||
fun getGradlewCommand(): String {
|
||||
val gradlewCommand: String
|
||||
val operatingSystem = System.getProperty("os.name").lowercase()
|
||||
gradlewCommand =
|
||||
if (operatingSystem.contains("win")) {
|
||||
".\\gradlew.bat"
|
||||
} else {
|
||||
"./gradlew"
|
||||
}
|
||||
return gradlewCommand
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse task and get inputs for this task
|
||||
*
|
||||
* @param task task to process
|
||||
* @return a list of inputs including external dependencies, null if empty or an error occurred
|
||||
*/
|
||||
fun getInputsForTask(
|
||||
task: Task,
|
||||
projectRoot: String,
|
||||
workspaceRoot: String,
|
||||
externalNodes: MutableMap<String, ExternalNode>?
|
||||
): MutableList<Any>? {
|
||||
return try {
|
||||
val mappedInputsIncludeExternal: MutableList<Any> = mutableListOf()
|
||||
val inputs = task.inputs
|
||||
val externalDependencies = mutableListOf<String>()
|
||||
inputs.sourceFiles.forEach { file ->
|
||||
val path: String = file.path
|
||||
// replace the absolute path to contain {projectRoot} or {workspaceRoot}
|
||||
val pathWithReplacedRoot = replaceRootInPath(path, projectRoot, workspaceRoot)
|
||||
if (pathWithReplacedRoot != null) { // if the path is inside workspace
|
||||
mappedInputsIncludeExternal.add((pathWithReplacedRoot))
|
||||
}
|
||||
// if the path is outside of workspace
|
||||
if (pathWithReplacedRoot == null &&
|
||||
externalNodes != null) { // add it to external dependencies
|
||||
try {
|
||||
val externalDep = getExternalDepFromInputFile(path, externalNodes, task.logger)
|
||||
externalDep?.let { externalDependencies.add(it) }
|
||||
} catch (e: Exception) {
|
||||
task.logger.info("${task}: get external dependency error $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (externalDependencies.isNotEmpty()) {
|
||||
mappedInputsIncludeExternal.add(mutableMapOf("externalDependencies" to externalDependencies))
|
||||
}
|
||||
if (mappedInputsIncludeExternal.isNotEmpty()) {
|
||||
return mappedInputsIncludeExternal
|
||||
}
|
||||
return null
|
||||
} catch (e: Exception) {
|
||||
// Log the error but don't fail the build
|
||||
task.logger.info("Error getting outputs for ${task.path}: ${e.message}")
|
||||
task.logger.debug("Stack trace:", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get outputs for task
|
||||
*
|
||||
* @param task task to process
|
||||
* @return list of outputs file, will not include if output file is outside workspace, null if empty
|
||||
* or an error occurred
|
||||
*/
|
||||
fun getOutputsForTask(task: Task, projectRoot: String, workspaceRoot: String): List<String>? {
|
||||
return try {
|
||||
val outputs = task.outputs.files
|
||||
if (!outputs.isEmpty) {
|
||||
return outputs.mapNotNull { file ->
|
||||
val path: String = file.path
|
||||
replaceRootInPath(path, projectRoot, workspaceRoot)
|
||||
}
|
||||
}
|
||||
null
|
||||
} catch (e: Exception) {
|
||||
// Log the error but don't fail the build
|
||||
task.logger.info("Error getting outputs for ${task.path}: ${e.message}")
|
||||
task.logger.debug("Stack trace:", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dependsOn for task, handling configuration timing safely. Rewrites dependency task names
|
||||
* based on targetNameOverrides (e.g., test -> ci).
|
||||
*
|
||||
* @param task task to process
|
||||
* @param dependencies optional set to collect inter-project Dependency objects
|
||||
* @param targetNameOverrides optional map of overrides (e.g., test -> ci)
|
||||
* @return list of dependsOn task names (possibly replaced), or null if none found or error occurred
|
||||
*/
|
||||
fun getDependsOnForTask(
|
||||
task: Task,
|
||||
dependencies: MutableSet<Dependency>?,
|
||||
targetNameOverrides: Map<String, String> = emptyMap()
|
||||
): List<String>? {
|
||||
|
||||
fun mapTasksToNames(tasks: Collection<Task>): List<String> {
|
||||
return tasks.map { depTask ->
|
||||
val depProject = depTask.project
|
||||
val taskProject = task.project
|
||||
|
||||
if (task.name != "buildDependents" && depProject != taskProject && dependencies != null) {
|
||||
dependencies.add(
|
||||
Dependency(
|
||||
taskProject.projectDir.path,
|
||||
depProject.projectDir.path,
|
||||
taskProject.buildFile.path))
|
||||
}
|
||||
|
||||
// Check if this task name needs to be overridden
|
||||
val taskName = targetNameOverrides.getOrDefault(depTask.name + "TargetName", depTask.name)
|
||||
val overriddenTaskName =
|
||||
if (depProject == taskProject) {
|
||||
taskName
|
||||
} else {
|
||||
"${depProject.name}:${taskName}"
|
||||
}
|
||||
|
||||
overriddenTaskName
|
||||
}
|
||||
}
|
||||
|
||||
return try {
|
||||
val dependsOnEntries = task.dependsOn
|
||||
|
||||
// Prefer task.dependsOn
|
||||
if (dependsOnEntries.isNotEmpty()) {
|
||||
val resolvedTasks =
|
||||
dependsOnEntries.flatMap { dep ->
|
||||
when (dep) {
|
||||
is Task -> listOf(dep)
|
||||
|
||||
is TaskProvider<*>,
|
||||
is NamedDomainObjectProvider<*> -> {
|
||||
val providerName = (dep as Named).name
|
||||
val foundTask = task.project.tasks.findByName(providerName)
|
||||
if (foundTask != null) {
|
||||
listOf(foundTask)
|
||||
} else {
|
||||
task.logger.info(
|
||||
"${dep::class.simpleName} '$providerName' did not resolve to a task in project ${task.project.name}")
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
is String -> {
|
||||
val foundTask = task.project.tasks.findByPath(dep)
|
||||
if (foundTask != null) {
|
||||
listOf(foundTask)
|
||||
} else {
|
||||
task.logger.info(
|
||||
"Task string '$dep' could not be resolved in project ${task.project.name}")
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
task.logger.info(
|
||||
"Unhandled dependency type ${dep::class.java} for task ${task.path}")
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resolvedTasks.isNotEmpty()) {
|
||||
return mapTasksToNames(resolvedTasks)
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: taskDependencies.getDependencies(task)
|
||||
val fallbackDeps =
|
||||
try {
|
||||
task.taskDependencies.getDependencies(null)
|
||||
} catch (e: Exception) {
|
||||
task.logger.info("Error calling getDependencies for ${task.path}: ${e.message}")
|
||||
task.logger.debug("Stack trace:", e)
|
||||
emptySet<Task>()
|
||||
}
|
||||
|
||||
if (fallbackDeps.isNotEmpty()) {
|
||||
return mapTasksToNames(fallbackDeps)
|
||||
}
|
||||
|
||||
null
|
||||
} catch (e: Exception) {
|
||||
task.logger.info("Unexpected error getting dependencies for ${task.path}: ${e.message}")
|
||||
task.logger.debug("Stack trace:", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata for task
|
||||
*
|
||||
* @param description
|
||||
*/
|
||||
fun getMetadata(
|
||||
description: String?,
|
||||
projectBuildPath: String,
|
||||
taskName: String,
|
||||
nonAtomizedTarget: String? = null
|
||||
): Map<String, Any?> {
|
||||
val gradlewCommand = getGradlewCommand()
|
||||
return mapOf(
|
||||
"description" to description,
|
||||
"technologies" to arrayOf("gradle"),
|
||||
"help" to mapOf("command" to "$gradlewCommand help --task ${projectBuildPath}:${taskName}"),
|
||||
"nonAtomizedTarget" to nonAtomizedTarget)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a file path like:
|
||||
* org.apache.commons/commons-lang3/3.13.0/b7263237aa89c1f99b327197c41d0669707a462e/commons-lang3-3.13.0.jar
|
||||
*
|
||||
* Into an external dependency with key: "gradle:commons-lang3-3.13.0" with value: { "type":
|
||||
* "gradle", "name": "commons-lang3", "data": { "version": "3.13.0", "packageName":
|
||||
* "org.apache.commons.commons-lang3", "hash": "b7263237aa89c1f99b327197c41d0669707a462e",} }
|
||||
*
|
||||
* @param inputFile Path to the dependency jar.
|
||||
* @param externalNodes Map to populate with the resulting ExternalNode.
|
||||
* @return The external dependency key (e.g., gradle:commons-lang3-3.13.0), or null if parsing
|
||||
* fails.
|
||||
*/
|
||||
fun getExternalDepFromInputFile(
|
||||
inputFile: String,
|
||||
externalNodes: MutableMap<String, ExternalNode>,
|
||||
logger: org.gradle.api.logging.Logger
|
||||
): String? {
|
||||
try {
|
||||
val segments = inputFile.split("/")
|
||||
|
||||
// Expecting at least 5 segments to safely extract group, package, version, hash, filename
|
||||
if (segments.size < 5) {
|
||||
logger.warn("Invalid input path: '$inputFile'. Expected at least 5 segments.")
|
||||
return null
|
||||
}
|
||||
|
||||
val fileName = segments.last()
|
||||
|
||||
// Remove any file extension (after the last dot), if present
|
||||
val nameKey = fileName.substringBeforeLast(".", fileName)
|
||||
|
||||
val hash = segments[segments.size - 2]
|
||||
val version = segments[segments.size - 3]
|
||||
val packageName = segments[segments.size - 4]
|
||||
val packageGroup = segments[segments.size - 5]
|
||||
|
||||
val fullPackageName = "$packageGroup.$packageName"
|
||||
|
||||
val data = ExternalDepData(version, fullPackageName, hash)
|
||||
val externalKey = "gradle:$nameKey"
|
||||
val node = ExternalNode("gradle", externalKey, data)
|
||||
|
||||
externalNodes[externalKey] = node
|
||||
|
||||
return externalKey
|
||||
} catch (e: Exception) {
|
||||
logger.warn("Failed to parse inputFile '$inputFile': ${e.message}")
|
||||
logger.debug("Stack trace:", e)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Going to replace the projectRoot with {projectRoot} and workspaceRoot with {workspaceRoot}
|
||||
*
|
||||
* @return mapped path if inside workspace, null if outside workspace
|
||||
*/
|
||||
fun replaceRootInPath(p: String, projectRoot: String, workspaceRoot: String): String? {
|
||||
var path = p
|
||||
if (path.startsWith(projectRoot)) {
|
||||
path = path.replace(projectRoot, "{projectRoot}")
|
||||
return path
|
||||
} else if (path.startsWith(workspaceRoot)) {
|
||||
path = path.replace(workspaceRoot, "{workspaceRoot}")
|
||||
return path
|
||||
}
|
||||
return null
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package dev.nx.gradle.utils
|
||||
|
||||
import dev.nx.gradle.data.Dependency
|
||||
import org.gradle.api.Project
|
||||
|
||||
private val dependencyCache = mutableMapOf<Project, Set<Dependency>>()
|
||||
|
||||
fun getDependenciesForProject(project: Project): MutableSet<Dependency> {
|
||||
return dependencyCache
|
||||
.getOrPut(project) { buildDependenciesForProject(project) }
|
||||
.toMutableSet() // Return a new mutable copy to prevent modifying the cached set
|
||||
}
|
||||
|
||||
private fun buildDependenciesForProject(project: Project): Set<Dependency> {
|
||||
val dependencies = mutableSetOf<Dependency>()
|
||||
|
||||
// Include subprojects manually
|
||||
project.subprojects.forEach { childProject ->
|
||||
dependencies.add(
|
||||
Dependency(project.projectDir.path, childProject.projectDir.path, project.buildFile.path))
|
||||
}
|
||||
|
||||
// Include included builds manually
|
||||
project.gradle.includedBuilds.forEach { includedBuild ->
|
||||
dependencies.add(
|
||||
Dependency(project.projectDir.path, includedBuild.projectDir.path, project.buildFile.path))
|
||||
}
|
||||
|
||||
return dependencies
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
package dev.nx.gradle.utils
|
||||
|
||||
import dev.nx.gradle.data.*
|
||||
import java.io.File
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class AddTestCiTargetsTest {
|
||||
|
||||
private lateinit var project: Project
|
||||
private lateinit var testTask: Task
|
||||
private lateinit var workspaceRoot: File
|
||||
private lateinit var projectRoot: File
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
workspaceRoot = createTempDir("workspace")
|
||||
projectRoot = File(workspaceRoot, "project-a").apply { mkdirs() }
|
||||
|
||||
project = ProjectBuilder.builder().withProjectDir(projectRoot).build()
|
||||
testTask = project.task("test")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should generate test CI targets and group correctly`() {
|
||||
val testFile1 =
|
||||
File(projectRoot, "src/test/kotlin/MyFirstTest.kt").apply {
|
||||
parentFile.mkdirs()
|
||||
writeText("@Test class MyFirstTest")
|
||||
}
|
||||
|
||||
val testFile2 =
|
||||
File(projectRoot, "src/test/kotlin/AnotherTest.kt").apply {
|
||||
parentFile.mkdirs()
|
||||
writeText("@Test class AnotherTest")
|
||||
}
|
||||
|
||||
val testFiles = project.files(testFile1, testFile2)
|
||||
|
||||
val targets = mutableMapOf<String, MutableMap<String, Any?>>()
|
||||
val targetGroups = mutableMapOf<String, MutableList<String>>()
|
||||
val ciTargetName = "ci"
|
||||
|
||||
addTestCiTargets(
|
||||
testFiles = testFiles,
|
||||
projectBuildPath = ":project-a",
|
||||
testTask = testTask,
|
||||
targets = targets,
|
||||
targetGroups = targetGroups,
|
||||
projectRoot = projectRoot.absolutePath,
|
||||
workspaceRoot = workspaceRoot.absolutePath,
|
||||
ciTargetName = ciTargetName)
|
||||
|
||||
// Assert each test file created a CI target
|
||||
assertTrue(targets.containsKey("ci--MyFirstTest"))
|
||||
assertTrue(targets.containsKey("ci--AnotherTest"))
|
||||
|
||||
// Assert test group contains individual targets and parent ci task
|
||||
val group = targetGroups[testCiTargetGroup]
|
||||
assertTrue(group != null)
|
||||
assertTrue(group!!.contains("ci--MyFirstTest"))
|
||||
assertTrue(group.contains("ci--AnotherTest"))
|
||||
assertTrue(group.contains("ci"))
|
||||
|
||||
// Assert parent CI task includes dependsOn
|
||||
val parentCi = targets["ci"]
|
||||
val dependsOn = parentCi?.get("dependsOn") as? List<*>
|
||||
assertEquals(2, dependsOn!!.size)
|
||||
|
||||
val firstTarget = targets["ci--MyFirstTest"]!!
|
||||
assertTrue(firstTarget["command"].toString().contains("--tests MyFirstTest"))
|
||||
assertEquals(true, firstTarget["cache"])
|
||||
assertTrue((firstTarget["inputs"] as Array<*>)[0].toString().contains("{projectRoot}"))
|
||||
assertEquals("nx:noop", parentCi["executor"])
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
package dev.nx.gradle.utils
|
||||
|
||||
import dev.nx.gradle.data.*
|
||||
import kotlin.test.*
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
|
||||
class CreateNodeForProjectTest {
|
||||
|
||||
@Test
|
||||
fun `should return GradleNodeReport with targets and metadata`() {
|
||||
// Arrange
|
||||
val workspaceRoot = createTempDir("workspace").absolutePath
|
||||
val projectDir = createTempDir("project")
|
||||
val project = ProjectBuilder.builder().withProjectDir(projectDir).build()
|
||||
|
||||
// Create a couple of dummy tasks
|
||||
project.task("compileJava").apply {
|
||||
group = "build"
|
||||
description = "Compiles Java sources"
|
||||
}
|
||||
|
||||
project.task("test").apply {
|
||||
group = "verification"
|
||||
description = "Runs the tests"
|
||||
}
|
||||
|
||||
val targetNameOverrides = mapOf<String, String>()
|
||||
|
||||
// Act
|
||||
val result =
|
||||
createNodeForProject(
|
||||
project = project,
|
||||
targetNameOverrides = targetNameOverrides,
|
||||
workspaceRoot = workspaceRoot,
|
||||
cwd = "{projectRoot}")
|
||||
|
||||
// Assert
|
||||
val projectRoot = project.projectDir.absolutePath
|
||||
assertTrue(result.nodes.containsKey(projectRoot), "Expected node for project root")
|
||||
|
||||
val projectNode = result.nodes[projectRoot]
|
||||
assertNotNull(projectNode, "ProjectNode should not be null")
|
||||
|
||||
// Check target metadata
|
||||
assertEquals(project.name, projectNode.name)
|
||||
assertNotNull(projectNode.targets["compileJava"], "Expected compileJava target")
|
||||
assertNotNull(projectNode.targets["test"], "Expected test target")
|
||||
assertEquals("build", projectNode.metadata.targetGroups.keys.firstOrNull())
|
||||
|
||||
// Dependencies and external nodes should default to empty
|
||||
assertTrue(result.dependencies.isEmpty(), "Expected no dependencies")
|
||||
assertTrue(result.externalNodes.isEmpty(), "Expected no external nodes")
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
package dev.nx.gradle.utils
|
||||
|
||||
import dev.nx.gradle.data.Dependency
|
||||
import dev.nx.gradle.data.ExternalNode
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
import org.junit.jupiter.api.Assertions.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.*
|
||||
|
||||
class ProcessTaskUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `test replaceRootInPath`() {
|
||||
val path = "/home/user/workspace/project/src/main/java"
|
||||
val projectRoot = "/home/user/workspace/project"
|
||||
val workspaceRoot = "/home/user/workspace"
|
||||
|
||||
assertEquals("{projectRoot}/src/main/java", replaceRootInPath(path, projectRoot, workspaceRoot))
|
||||
assertEquals(
|
||||
"{workspaceRoot}/project/src/main/java",
|
||||
replaceRootInPath(path, "/other/path", workspaceRoot))
|
||||
assertNull(replaceRootInPath("/external/other", projectRoot, workspaceRoot))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test getGradlewCommand`() {
|
||||
val command = getGradlewCommand()
|
||||
assertTrue(command.contains("gradlew"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test getMetadata`() {
|
||||
val metadata = getMetadata("Compile Java", ":project", "compileJava")
|
||||
assertEquals("Compile Java", metadata["description"])
|
||||
assertEquals("gradle", (metadata["technologies"] as Array<*>)[0])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test getExternalDepFromInputFile valid path`() {
|
||||
val externalNodes = mutableMapOf<String, ExternalNode>()
|
||||
val path = "org/apache/commons/commons-lang3/3.13.0/hash/commons-lang3-3.13.0.jar"
|
||||
|
||||
val key = getExternalDepFromInputFile(path, externalNodes, mock())
|
||||
|
||||
assertEquals("gradle:commons-lang3-3.13.0", key)
|
||||
assertTrue(externalNodes.containsKey("gradle:commons-lang3-3.13.0"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test getExternalDepFromInputFile invalid path`() {
|
||||
val externalNodes = mutableMapOf<String, ExternalNode>()
|
||||
val key = getExternalDepFromInputFile("invalid/path.jar", externalNodes, mock())
|
||||
|
||||
assertNull(key)
|
||||
assertTrue(externalNodes.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test getDependsOnForTask with direct dependsOn`() {
|
||||
val project = ProjectBuilder.builder().build()
|
||||
val taskA = project.tasks.register("taskA").get()
|
||||
val taskB = project.tasks.register("taskB").get()
|
||||
|
||||
taskA.dependsOn(taskB)
|
||||
|
||||
val dependencies = mutableSetOf<Dependency>()
|
||||
val dependsOn = getDependsOnForTask(taskA, dependencies)
|
||||
|
||||
assertNotNull(dependsOn)
|
||||
assertTrue(dependsOn!!.contains("taskB"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test processTask basic properties`() {
|
||||
val project = ProjectBuilder.builder().build()
|
||||
val task = project.tasks.register("compileJava").get()
|
||||
task.group = "build"
|
||||
task.description = "Compiles Java source files"
|
||||
|
||||
val result =
|
||||
processTask(
|
||||
task,
|
||||
projectBuildPath = ":project",
|
||||
projectRoot = project.projectDir.path,
|
||||
workspaceRoot = project.rootDir.path,
|
||||
cwd = ".",
|
||||
externalNodes = mutableMapOf(),
|
||||
dependencies = mutableSetOf(),
|
||||
targetNameOverrides = emptyMap())
|
||||
|
||||
assertEquals(true, result["cache"])
|
||||
assertTrue((result["command"] as String).contains("gradlew"))
|
||||
assertNotNull(result["metadata"])
|
||||
assertNotNull(result["options"])
|
||||
}
|
||||
}
|
||||
@ -13,7 +13,7 @@ jobs:
|
||||
_JAVA_OPTIONS: '-Xmx3g'
|
||||
GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2'
|
||||
docker:
|
||||
- image: cimg/openjdk:17.0-node
|
||||
- image: cimg/openjdk:21.0-node
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
@ -66,15 +66,15 @@ jobs:
|
||||
# Uncomment this line to enable task distribution
|
||||
# - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-jvm" --stop-agents-after="build"
|
||||
|
||||
- name: Set up JDK 17 for x64
|
||||
- name: Set up JDK 21 for x64
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
architecture: x64
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
uses: gradle/gradle-build-action@v4
|
||||
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
|
||||
@ -96,7 +96,7 @@ jobs:
|
||||
_JAVA_OPTIONS: '-Xmx3g'
|
||||
GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2'
|
||||
docker:
|
||||
- image: cimg/openjdk:17.0-node
|
||||
- image: cimg/openjdk:21.0-node
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
@ -149,15 +149,15 @@ jobs:
|
||||
# Connect your workspace by running "nx connect" and uncomment this line to enable task distribution
|
||||
# - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-jvm" --stop-agents-after="build"
|
||||
|
||||
- name: Set up JDK 17 for x64
|
||||
- name: Set up JDK 21 for x64
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
architecture: x64
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
uses: gradle/gradle-build-action@v4
|
||||
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ jobs:
|
||||
_JAVA_OPTIONS: "-Xmx3g"
|
||||
GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2"
|
||||
docker:
|
||||
- image: cimg/openjdk:17.0-node
|
||||
- image: cimg/openjdk:21.0-node
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
|
||||
@ -25,15 +25,15 @@ jobs:
|
||||
<% if (connectedToCloud) { %># Uncomment this line to enable task distribution<% } else { %># Connect your workspace by running "nx connect" and uncomment this line to enable task distribution<% } %>
|
||||
# - run: <%= packageManagerPrefix %> nx-cloud start-ci-run --distribute-on="3 linux-medium-jvm" --stop-agents-after="build"
|
||||
|
||||
- name: Set up JDK 17 for x64
|
||||
- name: Set up JDK 21 for x64
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
architecture: x64
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
uses: gradle/gradle-build-action@v4
|
||||
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
|
||||
|
||||
@ -24,7 +24,6 @@ describe('@nx/gradle:init', () => {
|
||||
"options": {
|
||||
"buildTargetName": "build",
|
||||
"classesTargetName": "classes",
|
||||
"includeSubprojectsTasks": false,
|
||||
"testTargetName": "test",
|
||||
},
|
||||
"plugin": "@nx/gradle",
|
||||
@ -49,7 +48,6 @@ describe('@nx/gradle:init', () => {
|
||||
"options": {
|
||||
"buildTargetName": "build",
|
||||
"classesTargetName": "classes",
|
||||
"includeSubprojectsTasks": false,
|
||||
"testTargetName": "test",
|
||||
},
|
||||
"plugin": "@nx/gradle",
|
||||
|
||||
@ -9,7 +9,11 @@ import {
|
||||
Tree,
|
||||
updateNxJson,
|
||||
} from '@nx/devkit';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import {
|
||||
gradleProjectGraphPluginName,
|
||||
gradleProjectGraphVersion,
|
||||
nxVersion,
|
||||
} from '../../utils/versions';
|
||||
import { InitGeneratorSchema } from './schema';
|
||||
import { hasGradlePlugin } from '../../utils/has-gradle-plugin';
|
||||
import { dirname, join, basename } from 'path';
|
||||
@ -52,7 +56,6 @@ function addPlugin(tree: Tree) {
|
||||
testTargetName: 'test',
|
||||
classesTargetName: 'classes',
|
||||
buildTargetName: 'build',
|
||||
includeSubprojectsTasks: false,
|
||||
},
|
||||
});
|
||||
updateNxJson(tree, nxJson);
|
||||
@ -67,16 +70,18 @@ export async function addBuildGradleFileNextToSettingsGradle(tree: Tree) {
|
||||
'**/settings.gradle?(.kts)',
|
||||
]);
|
||||
settingsGradleFiles.forEach((settingsGradleFile) => {
|
||||
addProjectReportToBuildGradle(settingsGradleFile, tree);
|
||||
addNxProjectGraphPluginToBuildGradle(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.
|
||||
* - adds the NxProjectGraphPlugin plugin to the build.gradle file if it does not exist.
|
||||
*/
|
||||
function addProjectReportToBuildGradle(settingsGradleFile: string, tree: Tree) {
|
||||
function addNxProjectGraphPluginToBuildGradle(
|
||||
settingsGradleFile: string,
|
||||
tree: Tree
|
||||
) {
|
||||
const filename = basename(settingsGradleFile);
|
||||
let gradleFilePath = 'build.gradle';
|
||||
if (filename.endsWith('.kts')) {
|
||||
@ -90,53 +95,49 @@ function addProjectReportToBuildGradle(settingsGradleFile: string, tree: Tree) {
|
||||
buildGradleContent = tree.read(gradleFilePath).toString();
|
||||
}
|
||||
|
||||
if (buildGradleContent.includes('allprojects')) {
|
||||
if (!buildGradleContent.includes('"project-report"')) {
|
||||
logger.warn(`Please add the project-report plugin to your ${gradleFilePath}:
|
||||
const nxProjectGraphReportPlugin = filename.endsWith('.kts')
|
||||
? `id("${gradleProjectGraphPluginName}") version("${gradleProjectGraphVersion}")`
|
||||
: `id "${gradleProjectGraphPluginName}" version "${gradleProjectGraphVersion}"`;
|
||||
if (buildGradleContent.includes('plugins {')) {
|
||||
if (!buildGradleContent.includes(gradleProjectGraphPluginName)) {
|
||||
buildGradleContent = buildGradleContent.replace(
|
||||
'plugins {',
|
||||
`plugins {
|
||||
${nxProjectGraphReportPlugin}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
buildGradleContent = `plugins {
|
||||
${nxProjectGraphReportPlugin}
|
||||
}\n\r${buildGradleContent}`;
|
||||
}
|
||||
|
||||
const applyNxProjectGraphReportPlugin = `plugin("${gradleProjectGraphPluginName}")`;
|
||||
if (buildGradleContent.includes('allprojects {')) {
|
||||
if (
|
||||
!buildGradleContent.includes(
|
||||
`plugin("${gradleProjectGraphPluginName}")`
|
||||
) &&
|
||||
!buildGradleContent.includes(`plugin('${gradleProjectGraphPluginName}')`)
|
||||
) {
|
||||
logger.warn(
|
||||
`Please add the ${gradleProjectGraphPluginName} plugin to your ${gradleFilePath}:
|
||||
allprojects {
|
||||
apply {
|
||||
plugin("project-report")
|
||||
${applyNxProjectGraphReportPlugin}
|
||||
}
|
||||
}`);
|
||||
}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
buildGradleContent += `\n\rallprojects {
|
||||
buildGradleContent = `${buildGradleContent}\n\rallprojects {
|
||||
apply {
|
||||
plugin("project-report")
|
||||
}
|
||||
}`;
|
||||
}
|
||||
|
||||
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"))
|
||||
${applyNxProjectGraphReportPlugin}
|
||||
}
|
||||
}`;
|
||||
}
|
||||
}
|
||||
if (buildGradleContent) {
|
||||
|
||||
tree.write(gradleFilePath, buildGradleContent);
|
||||
}
|
||||
}
|
||||
|
||||
export function updateNxJsonConfiguration(tree: Tree) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Tree } from '@nx/devkit';
|
||||
import { addBuildGradleFileNextToSettingsGradle } from '../../generators/init/init';
|
||||
import { globAsync, logger, Tree } from '@nx/devkit';
|
||||
import { basename, dirname, join } from 'node:path';
|
||||
|
||||
/**
|
||||
* This migration adds task `projectReportAll` to build.gradle files
|
||||
@ -7,3 +7,83 @@ import { addBuildGradleFileNextToSettingsGradle } from '../../generators/init/in
|
||||
export default async function update(tree: Tree) {
|
||||
await addBuildGradleFileNextToSettingsGradle(tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function creates and populate build.gradle file next to the settings.gradle file.
|
||||
*/
|
||||
export async function addBuildGradleFileNextToSettingsGradle(tree: Tree) {
|
||||
const settingsGradleFiles = await globAsync(tree, [
|
||||
'**/settings.gradle?(.kts)',
|
||||
]);
|
||||
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 = 'build.gradle';
|
||||
if (filename.endsWith('.kts')) {
|
||||
gradleFilePath = 'build.gradle.kts';
|
||||
}
|
||||
gradleFilePath = join(dirname(settingsGradleFile), gradleFilePath);
|
||||
let buildGradleContent = '';
|
||||
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 ${gradleFilePath}:
|
||||
allprojects {
|
||||
apply {
|
||||
plugin("project-report")
|
||||
}
|
||||
}`);
|
||||
}
|
||||
} else {
|
||||
buildGradleContent += `\n\rallprojects {
|
||||
apply {
|
||||
plugin("project-report")
|
||||
}
|
||||
}`;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
#### Add includeSubprojectsTasks to build.gradle File
|
||||
#### Add includeSubprojectsTasks to @nx/gradle Plugin Options
|
||||
|
||||
Add includeSubprojectsTasks to build.gradle file
|
||||
Add includeSubprojectsTasks to @nx/gradle plugin options in nx.json file
|
||||
|
||||
#### Sample Code Changes
|
||||
|
||||
Update import paths for `withModuleFederation` and `withModuleFederationForSSR`.
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="Before" %}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Tree, readNxJson, updateNxJson } from '@nx/devkit';
|
||||
import { hasGradlePlugin } from '../../utils/has-gradle-plugin';
|
||||
import { GradlePluginOptions } from '../../plugin/nodes';
|
||||
import { GradlePluginOptions } from '../../plugin-v1/nodes';
|
||||
|
||||
// This function add options includeSubprojectsTasks as true in nx.json for gradle plugin
|
||||
export default function update(tree: Tree) {
|
||||
|
||||
26
packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.md
Normal file
26
packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.md
Normal file
@ -0,0 +1,26 @@
|
||||
#### Change @nx/gradle plugin to @nx/gradle/plugin-v1
|
||||
|
||||
Change @nx/gradle plugin to version 1 in nx.json
|
||||
|
||||
#### Sample Code Changes
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="Before" %}
|
||||
|
||||
```json {% fileName="nx.json" %}
|
||||
{
|
||||
"plugins": ["@nx/gradle"]
|
||||
}
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% tab label="After" %}
|
||||
|
||||
```json {% highlightLines=[5] fileName="nx.json" %}
|
||||
{
|
||||
"plugins": ["@nx/gradle/plugin-v1"]
|
||||
}
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
@ -0,0 +1,57 @@
|
||||
import { Tree, readNxJson } from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import update from './change-plugin-to-v1';
|
||||
|
||||
describe('ChangePluginToV1', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeAll(() => {
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
});
|
||||
|
||||
it('should not add @nx/gradle plugin if it does not exist', async () => {
|
||||
tree.write('nx.json', JSON.stringify({ namedInputs: {} }));
|
||||
update(tree);
|
||||
expect(readNxJson(tree)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"namedInputs": {},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should change @nx/gradle to @nx/gradle/plugin-v1 plugin', async () => {
|
||||
tree.write('nx.json', JSON.stringify({ plugins: ['@nx/gradle'] }));
|
||||
update(tree);
|
||||
expect(readNxJson(tree)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"plugins": [
|
||||
"@nx/gradle/plugin-v1",
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should add change to @nx/gradle plugin with options', async () => {
|
||||
tree.write(
|
||||
'nx.json',
|
||||
JSON.stringify({
|
||||
plugins: [
|
||||
{ plugin: '@nx/gradle', options: { testTargetName: 'test' } },
|
||||
],
|
||||
})
|
||||
);
|
||||
update(tree);
|
||||
expect(readNxJson(tree)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"plugins": [
|
||||
{
|
||||
"options": {
|
||||
"testTargetName": "test",
|
||||
},
|
||||
"plugin": "@nx/gradle/plugin-v1",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
25
packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.ts
Normal file
25
packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { Tree, readNxJson, updateNxJson } from '@nx/devkit';
|
||||
import { hasGradlePlugin } from '../../utils/has-gradle-plugin';
|
||||
|
||||
/* This function changes the plugin to v1
|
||||
* Replace @nx/gradle with @nx/gradle/plugin-v1
|
||||
*/
|
||||
export default function update(tree: Tree) {
|
||||
const nxJson = readNxJson(tree);
|
||||
if (!nxJson) {
|
||||
return;
|
||||
}
|
||||
if (!hasGradlePlugin(tree)) {
|
||||
return;
|
||||
}
|
||||
let gradlePluginIndex = nxJson.plugins.findIndex((p) =>
|
||||
typeof p === 'string' ? p === '@nx/gradle' : p.plugin === '@nx/gradle'
|
||||
);
|
||||
let gradlePlugin = nxJson.plugins[gradlePluginIndex];
|
||||
if (typeof gradlePlugin === 'string') {
|
||||
nxJson.plugins[gradlePluginIndex] = '@nx/gradle/plugin-v1';
|
||||
} else {
|
||||
gradlePlugin.plugin = '@nx/gradle/plugin-v1';
|
||||
}
|
||||
updateNxJson(tree, nxJson);
|
||||
}
|
||||
96
packages/gradle/src/plugin-v1/dependencies.ts
Normal file
96
packages/gradle/src/plugin-v1/dependencies.ts
Normal file
@ -0,0 +1,96 @@
|
||||
import {
|
||||
CreateDependencies,
|
||||
CreateDependenciesContext,
|
||||
DependencyType,
|
||||
FileMap,
|
||||
RawProjectGraphDependency,
|
||||
validateDependency,
|
||||
} from '@nx/devkit';
|
||||
import { basename, dirname } from 'node:path';
|
||||
|
||||
import { getCurrentGradleReport } from './utils/get-gradle-report';
|
||||
import { GRADLE_BUILD_FILES } from '../utils/split-config-files';
|
||||
|
||||
export const createDependencies: CreateDependencies = async (
|
||||
_,
|
||||
context: CreateDependenciesContext
|
||||
) => {
|
||||
const gradleFiles: string[] = findGradleFiles(context.filesToProcess);
|
||||
if (gradleFiles.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const gradleDependenciesStart = performance.mark('gradleDependencies:start');
|
||||
const {
|
||||
gradleFileToGradleProjectMap,
|
||||
gradleProjectNameToProjectRootMap,
|
||||
gradleProjectToDepsMap,
|
||||
gradleProjectToChildProjects,
|
||||
} = getCurrentGradleReport();
|
||||
const dependencies: Set<RawProjectGraphDependency> = new Set();
|
||||
|
||||
for (const gradleFile of gradleFiles) {
|
||||
const gradleProject = gradleFileToGradleProjectMap.get(gradleFile);
|
||||
const projectName = Object.values(context.projects).find(
|
||||
(project) => project.root === dirname(gradleFile)
|
||||
)?.name;
|
||||
const dependedProjects: Set<string> =
|
||||
gradleProjectToDepsMap.get(gradleProject);
|
||||
|
||||
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;
|
||||
if (targetProjectName) {
|
||||
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) {
|
||||
const dependency: RawProjectGraphDependency = {
|
||||
source: projectName as string,
|
||||
target: childProject,
|
||||
type: DependencyType.static,
|
||||
sourceFile: gradleFile,
|
||||
};
|
||||
validateDependency(dependency, context);
|
||||
dependencies.add(dependency);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const gradleDependenciesEnd = performance.mark('gradleDependencies:end');
|
||||
performance.measure(
|
||||
'gradleDependencies',
|
||||
gradleDependenciesStart.name,
|
||||
gradleDependenciesEnd.name
|
||||
);
|
||||
|
||||
return Array.from(dependencies);
|
||||
};
|
||||
|
||||
function findGradleFiles(fileMap: FileMap): string[] {
|
||||
const gradleFiles: string[] = [];
|
||||
|
||||
for (const [_, files] of Object.entries(fileMap.projectFileMap)) {
|
||||
for (const file of files) {
|
||||
if (GRADLE_BUILD_FILES.has(basename(file.file))) {
|
||||
gradleFiles.push(file.file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gradleFiles;
|
||||
}
|
||||
587
packages/gradle/src/plugin-v1/nodes.spec.ts
Normal file
587
packages/gradle/src/plugin-v1/nodes.spec.ts
Normal file
@ -0,0 +1,587 @@
|
||||
import { CreateNodesContext } from '@nx/devkit';
|
||||
|
||||
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';
|
||||
import { type GradleReport } from './utils/get-gradle-report';
|
||||
|
||||
let gradleReport: GradleReport;
|
||||
jest.mock('./utils/get-gradle-report', () => {
|
||||
return {
|
||||
GRADLE_BUILD_FILES: new Set(['build.gradle', 'build.gradle.kts']),
|
||||
populateGradleReport: jest.fn().mockImplementation(() => void 0),
|
||||
getCurrentGradleReport: jest.fn().mockImplementation(() => gradleReport),
|
||||
};
|
||||
});
|
||||
|
||||
import { createNodesV2 } from './nodes';
|
||||
|
||||
describe('@nx/gradle/plugin-v1/nodes', () => {
|
||||
let createNodesFunction = createNodesV2[1];
|
||||
let context: CreateNodesContext;
|
||||
let tempFs: TempFs;
|
||||
let cwd: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
tempFs = new TempFs('test');
|
||||
gradleReport = {
|
||||
gradleFileToGradleProjectMap: new Map<string, string>([
|
||||
['proj/build.gradle', 'proj'],
|
||||
]),
|
||||
gradleProjectToDepsMap: new Map<string, Set<string>>(),
|
||||
gradleFileToOutputDirsMap: new Map<string, Map<string, string>>([
|
||||
['proj/build.gradle', new Map([['build', 'build']])],
|
||||
]),
|
||||
gradleProjectToTasksMap: new Map<string, Set<string>>([
|
||||
['proj', new Set(['test'])],
|
||||
]),
|
||||
gradleProjectToTasksTypeMap: new Map<string, Map<string, string>>([
|
||||
[
|
||||
'proj',
|
||||
new Map([
|
||||
['test', 'Verification'],
|
||||
['build', 'Build'],
|
||||
]),
|
||||
],
|
||||
]),
|
||||
gradleProjectToProjectName: new Map<string, string>([['proj', 'proj']]),
|
||||
gradleProjectNameToProjectRootMap: new Map<string, string>([
|
||||
['proj', 'proj'],
|
||||
]),
|
||||
gradleProjectToChildProjects: new Map<string, string[]>(),
|
||||
};
|
||||
cwd = process.cwd();
|
||||
process.chdir(tempFs.tempDir);
|
||||
context = {
|
||||
nxJsonConfiguration: {
|
||||
namedInputs: {
|
||||
default: ['{projectRoot}/**/*'],
|
||||
production: ['!{projectRoot}/**/*.spec.ts'],
|
||||
},
|
||||
},
|
||||
workspaceRoot: tempFs.tempDir,
|
||||
configFiles: [],
|
||||
};
|
||||
|
||||
await tempFs.createFiles({
|
||||
'proj/build.gradle': ``,
|
||||
gradlew: '',
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetModules();
|
||||
process.chdir(cwd);
|
||||
});
|
||||
|
||||
it('should create nodes based on gradle', async () => {
|
||||
const results = await createNodesFunction(
|
||||
['proj/build.gradle'],
|
||||
{
|
||||
buildTargetName: 'build',
|
||||
},
|
||||
context
|
||||
);
|
||||
|
||||
expect(results).toMatchInlineSnapshot(`
|
||||
[
|
||||
[
|
||||
"proj/build.gradle",
|
||||
{
|
||||
"projects": {
|
||||
"proj": {
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"Verification": [
|
||||
"test",
|
||||
],
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"name": "proj",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"test": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:test",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('should create nodes include subprojects tasks', async () => {
|
||||
const results = await createNodesFunction(
|
||||
['proj/build.gradle'],
|
||||
{
|
||||
buildTargetName: 'build',
|
||||
includeSubprojectsTasks: true,
|
||||
},
|
||||
context
|
||||
);
|
||||
|
||||
expect(results).toMatchInlineSnapshot(`
|
||||
[
|
||||
[
|
||||
"proj/build.gradle",
|
||||
{
|
||||
"projects": {
|
||||
"proj": {
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"Build": [
|
||||
"build",
|
||||
],
|
||||
"Verification": [
|
||||
"test",
|
||||
],
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"name": "proj",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"build": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:build",
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
"classes",
|
||||
"test",
|
||||
],
|
||||
"inputs": [
|
||||
"production",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:build",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
"outputs": [
|
||||
"build",
|
||||
],
|
||||
},
|
||||
"test": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:test",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('should create nodes based on gradle for nested project root', async () => {
|
||||
gradleReport = {
|
||||
gradleFileToGradleProjectMap: new Map<string, string>([
|
||||
['nested/nested/proj/build.gradle', 'proj'],
|
||||
]),
|
||||
gradleProjectToDepsMap: new Map<string, Set<string>>(),
|
||||
gradleFileToOutputDirsMap: new Map<string, Map<string, string>>([
|
||||
['nested/nested/proj/build.gradle', new Map([['build', 'build']])],
|
||||
]),
|
||||
gradleProjectToTasksMap: new Map<string, Set<string>>([
|
||||
['proj', new Set(['test'])],
|
||||
]),
|
||||
gradleProjectToTasksTypeMap: new Map<string, Map<string, string>>([
|
||||
['proj', new Map([['test', 'Verification']])],
|
||||
]),
|
||||
gradleProjectToProjectName: new Map<string, string>([['proj', 'proj']]),
|
||||
gradleProjectNameToProjectRootMap: new Map<string, string>([
|
||||
['proj', 'proj'],
|
||||
]),
|
||||
gradleProjectToChildProjects: new Map<string, string[]>(),
|
||||
};
|
||||
await tempFs.createFiles({
|
||||
'nested/nested/proj/build.gradle': ``,
|
||||
});
|
||||
|
||||
const results = await createNodesFunction(
|
||||
['nested/nested/proj/build.gradle'],
|
||||
{
|
||||
buildTargetName: 'build',
|
||||
},
|
||||
context
|
||||
);
|
||||
|
||||
expect(results).toMatchInlineSnapshot(`
|
||||
[
|
||||
[
|
||||
"nested/nested/proj/build.gradle",
|
||||
{
|
||||
"projects": {
|
||||
"nested/nested/proj": {
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"Verification": [
|
||||
"test",
|
||||
],
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"name": "proj",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"test": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:test",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
describe('with atomized tests targets', () => {
|
||||
beforeEach(async () => {
|
||||
gradleReport = {
|
||||
gradleFileToGradleProjectMap: new Map<string, string>([
|
||||
['nested/nested/proj/build.gradle', 'proj'],
|
||||
]),
|
||||
gradleProjectToDepsMap: new Map<string, Set<string>>(),
|
||||
gradleFileToOutputDirsMap: new Map<string, Map<string, string>>([
|
||||
['nested/nested/proj/build.gradle', new Map([['build', 'build']])],
|
||||
]),
|
||||
gradleProjectToTasksMap: new Map<string, Set<string>>([
|
||||
['proj', new Set(['test'])],
|
||||
]),
|
||||
gradleProjectToTasksTypeMap: new Map<string, Map<string, string>>([
|
||||
['proj', new Map([['test', 'Test']])],
|
||||
]),
|
||||
gradleProjectToProjectName: new Map<string, string>([['proj', 'proj']]),
|
||||
gradleProjectNameToProjectRootMap: new Map<string, string>([
|
||||
['proj', 'proj'],
|
||||
]),
|
||||
gradleProjectToChildProjects: new Map<string, string[]>(),
|
||||
};
|
||||
await tempFs.createFiles({
|
||||
'nested/nested/proj/build.gradle': ``,
|
||||
});
|
||||
await tempFs.createFiles({
|
||||
'proj/src/test/java/test/rootTest.java': ``,
|
||||
});
|
||||
await tempFs.createFiles({
|
||||
'nested/nested/proj/src/test/java/test/aTest.java': ``,
|
||||
});
|
||||
await tempFs.createFiles({
|
||||
'nested/nested/proj/src/test/java/test/bTest.java': ``,
|
||||
});
|
||||
await tempFs.createFiles({
|
||||
'nested/nested/proj/src/test/java/test/cTests.java': ``,
|
||||
});
|
||||
});
|
||||
|
||||
it('should create nodes with atomized tests targets based on gradle for nested project root', async () => {
|
||||
const results = await createNodesFunction(
|
||||
[
|
||||
'nested/nested/proj/build.gradle',
|
||||
'proj/src/test/java/test/rootTest.java',
|
||||
'nested/nested/proj/src/test/java/test/aTest.java',
|
||||
'nested/nested/proj/src/test/java/test/bTest.java',
|
||||
'nested/nested/proj/src/test/java/test/cTests.java',
|
||||
],
|
||||
{
|
||||
buildTargetName: 'build',
|
||||
ciTargetName: 'test-ci',
|
||||
},
|
||||
context
|
||||
);
|
||||
|
||||
expect(results).toMatchInlineSnapshot(`
|
||||
[
|
||||
[
|
||||
"nested/nested/proj/build.gradle",
|
||||
{
|
||||
"projects": {
|
||||
"nested/nested/proj": {
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"Test": [
|
||||
"test-ci--aTest",
|
||||
"test-ci--bTest",
|
||||
"test-ci--cTests",
|
||||
"test-ci",
|
||||
"test",
|
||||
],
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"name": "proj",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"test": {
|
||||
"cache": false,
|
||||
"command": "./gradlew proj:test",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
"test-ci": {
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "test-ci--aTest",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "test-ci--bTest",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "test-ci--cTests",
|
||||
},
|
||||
],
|
||||
"executor": "nx:noop",
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle Tests in CI",
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"nonAtomizedTarget": "test",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
},
|
||||
"test-ci--aTest": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:test --tests aTest",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test nested/nested/proj/src/test/java/test/aTest.java in CI",
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
"test-ci--bTest": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:test --tests bTest",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test nested/nested/proj/src/test/java/test/bTest.java in CI",
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
"test-ci--cTests": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:test --tests cTests",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test nested/nested/proj/src/test/java/test/cTests.java in CI",
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
435
packages/gradle/src/plugin-v1/nodes.ts
Normal file
435
packages/gradle/src/plugin-v1/nodes.ts
Normal file
@ -0,0 +1,435 @@
|
||||
import {
|
||||
CreateNodes,
|
||||
CreateNodesV2,
|
||||
CreateNodesContext,
|
||||
ProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
createNodesFromFiles,
|
||||
readJsonFile,
|
||||
writeJsonFile,
|
||||
CreateNodesFunction,
|
||||
logger,
|
||||
} from '@nx/devkit';
|
||||
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { basename, dirname, join } from 'node:path';
|
||||
import { workspaceDataDirectory } from 'nx/src/utils/cache-directory';
|
||||
import { findProjectForPath } from 'nx/src/devkit-internals';
|
||||
|
||||
import {
|
||||
populateGradleReport,
|
||||
getCurrentGradleReport,
|
||||
GradleReport,
|
||||
} from './utils/get-gradle-report';
|
||||
import { hashObject } from 'nx/src/hasher/file-hasher';
|
||||
import {
|
||||
gradleConfigAndTestGlob,
|
||||
gradleConfigGlob,
|
||||
splitConfigFiles,
|
||||
} from '../utils/split-config-files';
|
||||
import { getGradleExecFile, findGradlewFile } from '../utils/exec-gradle';
|
||||
|
||||
const cacheableTaskType = new Set(['Build', 'Verification']);
|
||||
const dependsOnMap = {
|
||||
build: ['^build', 'classes', 'test'],
|
||||
testClasses: ['classes'],
|
||||
test: ['testClasses'],
|
||||
classes: ['^classes'],
|
||||
};
|
||||
|
||||
interface GradleTask {
|
||||
type: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface GradlePluginOptions {
|
||||
includeSubprojectsTasks?: boolean; // default is false, show all gradle tasks in the project
|
||||
ciTargetName?: string;
|
||||
testTargetName?: string;
|
||||
classesTargetName?: string;
|
||||
buildTargetName?: string;
|
||||
[taskTargetName: string]: string | undefined | boolean;
|
||||
}
|
||||
|
||||
function normalizeOptions(options: GradlePluginOptions): GradlePluginOptions {
|
||||
options ??= {};
|
||||
options.testTargetName ??= 'test';
|
||||
options.classesTargetName ??= 'classes';
|
||||
options.buildTargetName ??= 'build';
|
||||
return options;
|
||||
}
|
||||
|
||||
type GradleTargets = Record<string, Partial<ProjectConfiguration>>;
|
||||
|
||||
function readTargetsCache(cachePath: string): GradleTargets {
|
||||
return existsSync(cachePath) ? readJsonFile(cachePath) : {};
|
||||
}
|
||||
|
||||
export function writeTargetsToCache(cachePath: string, results: GradleTargets) {
|
||||
writeJsonFile(cachePath, results);
|
||||
}
|
||||
|
||||
export const createNodesV2: CreateNodesV2<GradlePluginOptions> = [
|
||||
gradleConfigAndTestGlob,
|
||||
async (files, options, context) => {
|
||||
const { buildFiles, projectRoots, gradlewFiles, testFiles } =
|
||||
splitConfigFiles(files);
|
||||
const optionsHash = hashObject(options);
|
||||
const cachePath = join(
|
||||
workspaceDataDirectory,
|
||||
`gradle-${optionsHash}.hash`
|
||||
);
|
||||
const targetsCache = readTargetsCache(cachePath);
|
||||
|
||||
await populateGradleReport(
|
||||
context.workspaceRoot,
|
||||
gradlewFiles.map((f) => join(context.workspaceRoot, f))
|
||||
);
|
||||
const gradleReport = getCurrentGradleReport();
|
||||
const gradleProjectRootToTestFilesMap = getGradleProjectRootToTestFilesMap(
|
||||
testFiles,
|
||||
projectRoots
|
||||
);
|
||||
|
||||
try {
|
||||
return createNodesFromFiles(
|
||||
makeCreateNodesForGradleConfigFile(
|
||||
gradleReport,
|
||||
targetsCache,
|
||||
gradleProjectRootToTestFilesMap
|
||||
),
|
||||
buildFiles,
|
||||
options,
|
||||
context
|
||||
);
|
||||
} finally {
|
||||
writeTargetsToCache(cachePath, targetsCache);
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
export const makeCreateNodesForGradleConfigFile =
|
||||
(
|
||||
gradleReport: GradleReport,
|
||||
targetsCache: GradleTargets = {},
|
||||
gradleProjectRootToTestFilesMap: Record<string, string[]> = {}
|
||||
): CreateNodesFunction =>
|
||||
async (
|
||||
gradleFilePath,
|
||||
options: GradlePluginOptions | undefined,
|
||||
context: CreateNodesContext
|
||||
) => {
|
||||
const projectRoot = dirname(gradleFilePath);
|
||||
options = normalizeOptions(options);
|
||||
|
||||
const hash = await calculateHashForCreateNodes(
|
||||
projectRoot,
|
||||
options ?? {},
|
||||
context
|
||||
);
|
||||
targetsCache[hash] ??= await createGradleProject(
|
||||
gradleReport,
|
||||
gradleFilePath,
|
||||
options,
|
||||
context,
|
||||
gradleProjectRootToTestFilesMap[projectRoot]
|
||||
);
|
||||
const project = targetsCache[hash];
|
||||
if (!project) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
projects: {
|
||||
[projectRoot]: project,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@deprecated This is replaced with {@link createNodesV2}. Update your plugin to export its own `createNodesV2` function that wraps this one instead.
|
||||
This function will change to the v2 function in Nx 20.
|
||||
*/
|
||||
export const createNodes: CreateNodes<GradlePluginOptions> = [
|
||||
gradleConfigGlob,
|
||||
async (buildFile, options, context) => {
|
||||
logger.warn(
|
||||
'`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.'
|
||||
);
|
||||
const { gradlewFiles } = splitConfigFiles(context.configFiles);
|
||||
await populateGradleReport(context.workspaceRoot, gradlewFiles);
|
||||
const gradleReport = getCurrentGradleReport();
|
||||
const internalCreateNodes =
|
||||
makeCreateNodesForGradleConfigFile(gradleReport);
|
||||
return await internalCreateNodes(buildFile, options, context);
|
||||
},
|
||||
];
|
||||
|
||||
async function createGradleProject(
|
||||
gradleReport: GradleReport,
|
||||
gradleFilePath: string,
|
||||
options: GradlePluginOptions | undefined,
|
||||
context: CreateNodesContext,
|
||||
testFiles = []
|
||||
) {
|
||||
try {
|
||||
const {
|
||||
gradleProjectToTasksTypeMap,
|
||||
gradleProjectToTasksMap,
|
||||
gradleFileToOutputDirsMap,
|
||||
gradleFileToGradleProjectMap,
|
||||
gradleProjectToProjectName,
|
||||
} = gradleReport;
|
||||
|
||||
const gradleProject = gradleFileToGradleProjectMap.get(
|
||||
gradleFilePath
|
||||
) as string;
|
||||
const projectName = gradleProjectToProjectName.get(gradleProject);
|
||||
if (!projectName) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tasksTypeMap: Map<string, string> = gradleProjectToTasksTypeMap.get(
|
||||
gradleProject
|
||||
) as Map<string, string>;
|
||||
const tasksSet = gradleProjectToTasksMap.get(gradleProject) as Set<string>;
|
||||
let tasks: GradleTask[] = [];
|
||||
tasksSet.forEach((taskName) => {
|
||||
tasks.push({
|
||||
type: tasksTypeMap?.get(taskName) as string,
|
||||
name: taskName,
|
||||
});
|
||||
});
|
||||
if (options.includeSubprojectsTasks) {
|
||||
tasksTypeMap.forEach((taskType, taskName) => {
|
||||
if (!tasksSet.has(taskName)) {
|
||||
tasks.push({
|
||||
type: taskType,
|
||||
name: taskName,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const outputDirs = gradleFileToOutputDirsMap.get(gradleFilePath) as Map<
|
||||
string,
|
||||
string
|
||||
>;
|
||||
|
||||
const { targets, targetGroups } = await createGradleTargets(
|
||||
tasks,
|
||||
options,
|
||||
context,
|
||||
outputDirs,
|
||||
gradleProject,
|
||||
gradleFilePath,
|
||||
testFiles
|
||||
);
|
||||
const project: Partial<ProjectConfiguration> = {
|
||||
name: projectName,
|
||||
projectType: 'application',
|
||||
targets,
|
||||
metadata: {
|
||||
targetGroups,
|
||||
technologies: ['gradle'],
|
||||
},
|
||||
};
|
||||
|
||||
return project;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async function createGradleTargets(
|
||||
tasks: GradleTask[],
|
||||
options: GradlePluginOptions | undefined,
|
||||
context: CreateNodesContext,
|
||||
outputDirs: Map<string, string>,
|
||||
gradleProject: string,
|
||||
gradleBuildFilePath: string,
|
||||
testFiles: string[] = []
|
||||
): Promise<{
|
||||
targetGroups: Record<string, string[]>;
|
||||
targets: Record<string, TargetConfiguration>;
|
||||
}> {
|
||||
const inputsMap = createInputsMap(context);
|
||||
const gradlewFileDirectory = dirname(
|
||||
findGradlewFile(gradleBuildFilePath, context.workspaceRoot)
|
||||
);
|
||||
|
||||
const targets: Record<string, TargetConfiguration> = {};
|
||||
const targetGroups: Record<string, string[]> = {};
|
||||
for (const task of tasks) {
|
||||
const targetName = options?.[`${task.name}TargetName`] ?? task.name;
|
||||
|
||||
let outputs = [outputDirs.get(task.name)].filter(Boolean);
|
||||
if (task.name === 'test') {
|
||||
outputs = [
|
||||
outputDirs.get('testReport'),
|
||||
outputDirs.get('testResults'),
|
||||
].filter(Boolean);
|
||||
getTestCiTargets(
|
||||
testFiles,
|
||||
gradleProject,
|
||||
targetName as string,
|
||||
options.ciTargetName,
|
||||
inputsMap['test'],
|
||||
outputs,
|
||||
task.type,
|
||||
targets,
|
||||
targetGroups,
|
||||
gradlewFileDirectory
|
||||
);
|
||||
}
|
||||
|
||||
const taskCommandToRun = `${gradleProject ? gradleProject + ':' : ''}${
|
||||
task.name
|
||||
}`;
|
||||
|
||||
targets[targetName as string] = {
|
||||
command: `${getGradleExecFile()} ${taskCommandToRun}`,
|
||||
options: {
|
||||
cwd: gradlewFileDirectory,
|
||||
},
|
||||
cache: cacheableTaskType.has(task.type),
|
||||
inputs: inputsMap[task.name],
|
||||
dependsOn: dependsOnMap[task.name],
|
||||
metadata: {
|
||||
technologies: ['gradle'],
|
||||
help: {
|
||||
command: `${getGradleExecFile()} help --task ${taskCommandToRun}`,
|
||||
example: {
|
||||
options: {
|
||||
args: ['--rerun'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
...(outputs && outputs.length ? { outputs } : {}),
|
||||
};
|
||||
|
||||
if (task.type) {
|
||||
if (!targetGroups[task.type]) {
|
||||
targetGroups[task.type] = [];
|
||||
}
|
||||
targetGroups[task.type].push(targetName as string);
|
||||
}
|
||||
}
|
||||
return { targetGroups, targets };
|
||||
}
|
||||
|
||||
function createInputsMap(
|
||||
context: CreateNodesContext
|
||||
): Record<string, TargetConfiguration['inputs']> {
|
||||
const namedInputs = context.nxJsonConfiguration.namedInputs;
|
||||
return {
|
||||
build: namedInputs?.production
|
||||
? ['production', '^production']
|
||||
: ['default', '^default'],
|
||||
test: ['default', namedInputs?.production ? '^production' : '^default'],
|
||||
classes: namedInputs?.production
|
||||
? ['production', '^production']
|
||||
: ['default', '^default'],
|
||||
};
|
||||
}
|
||||
|
||||
function getTestCiTargets(
|
||||
testFiles: string[],
|
||||
gradleProject: string,
|
||||
testTargetName: string,
|
||||
ciTargetName: string,
|
||||
inputs: TargetConfiguration['inputs'],
|
||||
outputs: string[],
|
||||
targetGroupName: string,
|
||||
targets: Record<string, TargetConfiguration>,
|
||||
targetGroups: Record<string, string[]>,
|
||||
gradlewFileDirectory: string
|
||||
): void {
|
||||
if (!testFiles || testFiles.length === 0 || !ciTargetName) {
|
||||
return;
|
||||
}
|
||||
const taskCommandToRun = `${gradleProject ? gradleProject + ':' : ''}test`;
|
||||
|
||||
if (!targetGroups[targetGroupName]) {
|
||||
targetGroups[targetGroupName] = [];
|
||||
}
|
||||
|
||||
const dependsOn: TargetConfiguration['dependsOn'] = [];
|
||||
testFiles.forEach((testFile) => {
|
||||
const testName = basename(testFile).split('.')[0];
|
||||
const targetName = ciTargetName + '--' + testName;
|
||||
|
||||
targets[targetName] = {
|
||||
command: `${getGradleExecFile()} ${taskCommandToRun} --tests ${testName}`,
|
||||
options: {
|
||||
cwd: gradlewFileDirectory,
|
||||
},
|
||||
cache: true,
|
||||
inputs,
|
||||
dependsOn: dependsOnMap['test'],
|
||||
metadata: {
|
||||
technologies: ['gradle'],
|
||||
description: `Runs Gradle test ${testFile} in CI`,
|
||||
help: {
|
||||
command: `${getGradleExecFile()} help --task ${taskCommandToRun}`,
|
||||
example: {
|
||||
options: {
|
||||
args: ['--rerun'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
...(outputs && outputs.length > 0 ? { outputs } : {}),
|
||||
};
|
||||
targetGroups[targetGroupName].push(targetName);
|
||||
dependsOn.push({
|
||||
target: targetName,
|
||||
projects: 'self',
|
||||
params: 'forward',
|
||||
});
|
||||
});
|
||||
|
||||
targets[ciTargetName] = {
|
||||
executor: 'nx:noop',
|
||||
cache: true,
|
||||
inputs,
|
||||
dependsOn: dependsOn,
|
||||
...(outputs && outputs.length > 0 ? { outputs } : {}),
|
||||
metadata: {
|
||||
technologies: ['gradle'],
|
||||
description: 'Runs Gradle Tests in CI',
|
||||
nonAtomizedTarget: testTargetName,
|
||||
help: {
|
||||
command: `${getGradleExecFile()} help --task ${taskCommandToRun}`,
|
||||
example: {
|
||||
options: {
|
||||
args: ['--rerun'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
targetGroups[targetGroupName].push(ciTargetName);
|
||||
}
|
||||
|
||||
function getGradleProjectRootToTestFilesMap(
|
||||
testFiles: string[],
|
||||
projectRoots: string[]
|
||||
): Record<string, string[]> | undefined {
|
||||
if (testFiles.length === 0 || projectRoots.length === 0) {
|
||||
return;
|
||||
}
|
||||
const roots = new Map(projectRoots.map((root) => [root, root]));
|
||||
const testFilesToGradleProjectMap: Record<string, string[]> = {};
|
||||
testFiles.forEach((testFile) => {
|
||||
const projectRoot = findProjectForPath(testFile, roots);
|
||||
if (projectRoot) {
|
||||
if (!testFilesToGradleProjectMap[projectRoot]) {
|
||||
testFilesToGradleProjectMap[projectRoot] = [];
|
||||
}
|
||||
testFilesToGradleProjectMap[projectRoot].push(testFile);
|
||||
}
|
||||
});
|
||||
return testFilesToGradleProjectMap;
|
||||
}
|
||||
@ -1,8 +1,5 @@
|
||||
> Task :dependencyReport
|
||||
See the report at: file:///tmp/build/reports/project/dependencies.txt
|
||||
|
||||
> Task :htmlDependencyReport
|
||||
See the report at: file:///tmp/build/reports/project/dependencies/index.html
|
||||
See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt
|
||||
|
||||
> Task :propertyReport
|
||||
See the report at: file:///tmp/build/reports/project/properties.txt
|
||||
@ -11,10 +8,7 @@ See the report at: file:///tmp/build/reports/project/properties.txt
|
||||
See the report at: file:///tmp/build/reports/project/tasks.txt
|
||||
|
||||
> Task :app:dependencyReport
|
||||
See the report at: file:///tmp/app/build/reports/project/dependencies.txt
|
||||
|
||||
> Task :app:htmlDependencyReport
|
||||
See the report at: file:///tmp/app/build/reports/project/dependencies/index.html
|
||||
See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt
|
||||
|
||||
> Task :app:propertyReport
|
||||
See the report at: file:///tmp/app/build/reports/project/properties.txt
|
||||
@ -25,10 +19,7 @@ NAMED TASK1: This is executed during the configuration phase
|
||||
See the report at: file:///tmp/app/build/reports/project/tasks.txt
|
||||
|
||||
> Task :list:dependencyReport
|
||||
See the report at: file:///tmp/list/build/reports/project/dependencies.txt
|
||||
|
||||
> Task :list:htmlDependencyReport
|
||||
See the report at: file:///tmp/list/build/reports/project/dependencies/index.html
|
||||
See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt
|
||||
|
||||
> Task :list:propertyReport
|
||||
See the report at: file:///tmp/list/build/reports/project/properties.txt
|
||||
@ -37,10 +28,7 @@ See the report at: file:///tmp/list/build/reports/project/properties.txt
|
||||
See the report at: file:///tmp/list/build/reports/project/tasks.txt
|
||||
|
||||
> Task :utilities:dependencyReport
|
||||
See the report at: file:///tmp/utilities/build/reports/project/dependencies.txt
|
||||
|
||||
> Task :utilities:htmlDependencyReport
|
||||
See the report at: file:///tmp/utilities/build/reports/project/dependencies/index.html
|
||||
See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt
|
||||
|
||||
> Task :utilities:propertyReport
|
||||
See the report at: file:///tmp/utilities/build/reports/project/properties.txt
|
||||
@ -1,5 +1,5 @@
|
||||
> Task :dependencyReport
|
||||
See the report at: file:///tmp/build/reports/project/dependencies.txt
|
||||
See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt
|
||||
|
||||
> Task :htmlDependencyReport
|
||||
See the report at: file:///tmp/build/reports/project/dependencies/index.html
|
||||
@ -11,10 +11,7 @@ See the report at: file:///tmp/build/reports/project/properties.txt
|
||||
See the report at: file:///tmp/build/reports/project/tasks.txt
|
||||
|
||||
> Task :app:dependencyReport
|
||||
See the report at: file:///tmp/app/build/reports/project/dependencies.txt
|
||||
|
||||
> Task :app:htmlDependencyReport
|
||||
See the report at: file:///tmp/app/build/reports/project/dependencies/index.html
|
||||
See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt
|
||||
|
||||
> Task :app:propertyReport
|
||||
See the report at: file:///tmp/app/build/reports/project/properties.txt
|
||||
@ -23,7 +20,7 @@ See the report at: file:///tmp/app/build/reports/project/properties.txt
|
||||
See the report at: file:///tmp/app/build/reports/project/tasks.txt
|
||||
|
||||
> Task :list:dependencyReport
|
||||
See the report at: file:///tmp/list/build/reports/project/dependencies.txt
|
||||
See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt
|
||||
|
||||
> Task :list:htmlDependencyReport
|
||||
See the report at: file:///tmp/list/build/reports/project/dependencies/index.html
|
||||
@ -35,10 +32,7 @@ See the report at: file:///tmp/list/build/reports/project/properties.txt
|
||||
See the report at: file:///tmp/list/build/reports/project/tasks.txt
|
||||
|
||||
> Task :utilities:dependencyReport
|
||||
See the report at: file:///tmp/utilities/build/reports/project/dependencies.txt
|
||||
|
||||
> Task :utilities:htmlDependencyReport
|
||||
See the report at: file:///tmp/utilities/build/reports/project/dependencies/index.html
|
||||
See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt
|
||||
|
||||
> Task :utilities:propertyReport
|
||||
See the report at: file:///tmp/utilities/build/reports/project/properties.txt
|
||||
@ -1,31 +1,103 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { fileSync } from 'tmp';
|
||||
import { join } from 'path';
|
||||
import {
|
||||
processGradleDependencies,
|
||||
processProjectReports,
|
||||
writeGradleReportToCache,
|
||||
} from './get-gradle-report';
|
||||
|
||||
describe('processProjectReports', () => {
|
||||
const tmpFile = fileSync();
|
||||
|
||||
it('should process project reports', () => {
|
||||
const projectReportLines = readFileSync(
|
||||
join(__dirname, '__mocks__/gradle-project-report.txt'),
|
||||
'utf-8'
|
||||
).split('\n');
|
||||
)
|
||||
.replaceAll('__dirname__', __dirname)
|
||||
.split('\n');
|
||||
const report = processProjectReports(projectReportLines);
|
||||
expect(
|
||||
Object.keys(Object.fromEntries(report.gradleProjectToTasksTypeMap))
|
||||
).toEqual(['', ':app', ':list', ':utilities']);
|
||||
|
||||
writeGradleReportToCache(tmpFile.name, report);
|
||||
expect(readFileSync(tmpFile.name).toString()).toMatchInlineSnapshot(`
|
||||
"{
|
||||
"gradleFileToGradleProjectMap": {},
|
||||
"gradleProjectToDepsMap": {
|
||||
"": [
|
||||
":utilities"
|
||||
],
|
||||
":app": [
|
||||
":utilities"
|
||||
],
|
||||
":list": [
|
||||
":utilities"
|
||||
],
|
||||
":utilities": [
|
||||
":utilities"
|
||||
]
|
||||
},
|
||||
"gradleFileToOutputDirsMap": {},
|
||||
"gradleProjectToTasksTypeMap": {
|
||||
"": {},
|
||||
":app": {},
|
||||
":list": {},
|
||||
":utilities": {}
|
||||
},
|
||||
"gradleProjectToTasksMap": {},
|
||||
"gradleProjectToProjectName": {},
|
||||
"gradleProjectNameToProjectRootMap": {},
|
||||
"gradleProjectToChildProjects": {}
|
||||
}"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should process project reports with println', () => {
|
||||
const projectReportLines = readFileSync(
|
||||
join(__dirname, '__mocks__/gradle-project-report-println.txt'),
|
||||
'utf-8'
|
||||
).split('\n');
|
||||
)
|
||||
.replaceAll('__dirname__', __dirname)
|
||||
.split('\n');
|
||||
const report = processProjectReports(projectReportLines);
|
||||
expect(
|
||||
Object.keys(Object.fromEntries(report.gradleProjectToTasksTypeMap))
|
||||
).toEqual(['', ':app', ':list', ':utilities']);
|
||||
|
||||
writeGradleReportToCache(tmpFile.name, report);
|
||||
expect(readFileSync(tmpFile.name).toString()).toMatchInlineSnapshot(`
|
||||
"{
|
||||
"gradleFileToGradleProjectMap": {},
|
||||
"gradleProjectToDepsMap": {
|
||||
"": [
|
||||
":utilities"
|
||||
],
|
||||
":app": [
|
||||
":utilities"
|
||||
],
|
||||
":list": [
|
||||
":utilities"
|
||||
],
|
||||
":utilities": [
|
||||
":utilities"
|
||||
]
|
||||
},
|
||||
"gradleFileToOutputDirsMap": {},
|
||||
"gradleProjectToTasksTypeMap": {
|
||||
"": {},
|
||||
":app": {},
|
||||
":list": {},
|
||||
":utilities": {}
|
||||
},
|
||||
"gradleProjectToTasksMap": {},
|
||||
"gradleProjectToProjectName": {},
|
||||
"gradleProjectNameToProjectRootMap": {},
|
||||
"gradleProjectToChildProjects": {}
|
||||
}"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should process properties report with child projects', () => {
|
||||
@ -11,18 +11,15 @@ import {
|
||||
|
||||
import { hashWithWorkspaceContext } from 'nx/src/utils/workspace-context';
|
||||
import { dirname } from 'path';
|
||||
import { gradleConfigAndTestGlob } from './split-config-files';
|
||||
import {
|
||||
getProjectReportLines,
|
||||
fileSeparator,
|
||||
newLineSeparator,
|
||||
} from './get-project-report-lines';
|
||||
import { gradleConfigAndTestGlob } from '../../utils/split-config-files';
|
||||
import { getProjectReportLines } from './get-project-report-lines';
|
||||
import { workspaceDataDirectory } from 'nx/src/utils/cache-directory';
|
||||
import { fileSeparator, newLineSeparator } from '../../utils/exec-gradle';
|
||||
|
||||
export interface GradleReport {
|
||||
gradleFileToGradleProjectMap: Map<string, string>;
|
||||
buildFileToDepsMap: Map<string, Set<string>>;
|
||||
gradleFileToOutputDirsMap: Map<string, Map<string, string>>;
|
||||
gradleProjectToDepsMap: Map<string, Set<string>>;
|
||||
gradleProjectToTasksTypeMap: Map<string, Map<string, string>>;
|
||||
gradleProjectToTasksMap: Map<string, Set<string>>;
|
||||
gradleProjectToProjectName: Map<string, string>;
|
||||
@ -33,7 +30,7 @@ export interface GradleReport {
|
||||
export interface GradleReportJSON {
|
||||
hash: string;
|
||||
gradleFileToGradleProjectMap: Record<string, string>;
|
||||
buildFileToDepsMap: Record<string, Set<string>>;
|
||||
gradleProjectToDepsMap: Record<string, Array<string>>;
|
||||
gradleFileToOutputDirsMap: Record<string, Record<string, string>>;
|
||||
gradleProjectToTasksTypeMap: Record<string, Record<string, string>>;
|
||||
gradleProjectToTasksMap: Record<string, Array<string>>;
|
||||
@ -56,8 +53,10 @@ function readGradleReportCache(
|
||||
gradleFileToGradleProjectMap: new Map(
|
||||
Object.entries(gradleReportJson['gradleFileToGradleProjectMap'])
|
||||
),
|
||||
buildFileToDepsMap: new Map(
|
||||
Object.entries(gradleReportJson['buildFileToDepsMap'])
|
||||
gradleProjectToDepsMap: new Map(
|
||||
Object.entries(gradleReportJson['gradleProjectToDepsMap']).map(
|
||||
([key, value]) => [key, new Set(value)]
|
||||
)
|
||||
),
|
||||
gradleFileToOutputDirsMap: new Map(
|
||||
Object.entries(gradleReportJson['gradleFileToOutputDirsMap']).map(
|
||||
@ -96,7 +95,12 @@ export function writeGradleReportToCache(
|
||||
gradleFileToGradleProjectMap: Object.fromEntries(
|
||||
results.gradleFileToGradleProjectMap
|
||||
),
|
||||
buildFileToDepsMap: Object.fromEntries(results.buildFileToDepsMap),
|
||||
gradleProjectToDepsMap: Object.fromEntries(
|
||||
Array.from(results.gradleProjectToDepsMap).map(([key, value]) => [
|
||||
key,
|
||||
Array.from(value),
|
||||
])
|
||||
),
|
||||
gradleFileToOutputDirsMap: Object.fromEntries(
|
||||
Array.from(results.gradleFileToOutputDirsMap).map(([key, value]) => [
|
||||
key,
|
||||
@ -215,7 +219,7 @@ export function processProjectReports(
|
||||
* Map of Gradle File path to Gradle Project Name
|
||||
*/
|
||||
const gradleFileToGradleProjectMap = new Map<string, string>();
|
||||
const dependenciesMap = new Map<string, string>();
|
||||
const gradleProjectToDepsMap = new Map<string, Set<string>>();
|
||||
/**
|
||||
* Map of Gradle Build File to tasks type map
|
||||
*/
|
||||
@ -223,10 +227,6 @@ export function processProjectReports(
|
||||
const gradleProjectToTasksMap = new Map<string, Set<string>>();
|
||||
const gradleProjectToProjectName = new Map<string, string>();
|
||||
const gradleProjectNameToProjectRootMap = new Map<string, string>();
|
||||
/**
|
||||
* Map of buildFile to dependencies report path
|
||||
*/
|
||||
const buildFileToDepsMap = new Map<string, Set<string>>();
|
||||
/**
|
||||
* Map fo possible output files of each gradle file
|
||||
* e.g. {build.gradle.kts: { projectReportDir: '' testReportDir: '' }}
|
||||
@ -253,7 +253,10 @@ export function processProjectReports(
|
||||
index++;
|
||||
}
|
||||
const [_, file] = projectReportLines[index].split(fileSeparator);
|
||||
dependenciesMap.set(gradleProject, file);
|
||||
gradleProjectToDepsMap.set(
|
||||
gradleProject,
|
||||
processGradleDependencies(file)
|
||||
);
|
||||
}
|
||||
if (line.endsWith('propertyReport')) {
|
||||
const gradleProject = line.substring(
|
||||
@ -320,13 +323,6 @@ export function processProjectReports(
|
||||
relative(workspaceRoot, absBuildFilePath)
|
||||
);
|
||||
const buildDir = relative(workspaceRoot, absBuildDirPath);
|
||||
const depsFile = dependenciesMap.get(gradleProject);
|
||||
if (depsFile) {
|
||||
buildFileToDepsMap.set(
|
||||
buildFile,
|
||||
processGradleDependencies(depsFile)
|
||||
);
|
||||
}
|
||||
|
||||
outputDirMap.set('build', `{workspaceRoot}/${buildDir}`);
|
||||
outputDirMap.set(
|
||||
@ -389,9 +385,9 @@ export function processProjectReports(
|
||||
|
||||
return {
|
||||
gradleFileToGradleProjectMap,
|
||||
buildFileToDepsMap,
|
||||
gradleFileToOutputDirsMap,
|
||||
gradleProjectToTasksTypeMap,
|
||||
gradleProjectToDepsMap,
|
||||
gradleProjectToTasksMap,
|
||||
gradleProjectToProjectName,
|
||||
gradleProjectNameToProjectRootMap,
|
||||
@ -1,16 +1,7 @@
|
||||
import { AggregateCreateNodesError, logger, output } from '@nx/devkit';
|
||||
import { execGradleAsync } from './exec-gradle';
|
||||
import { execGradleAsync, newLineSeparator } from '../../utils/exec-gradle';
|
||||
import { existsSync } from 'fs';
|
||||
import { dirname, join } from 'path';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
export const fileSeparator = process.platform.startsWith('win')
|
||||
? 'file:///'
|
||||
: 'file://';
|
||||
|
||||
export const newLineSeparator = process.platform.startsWith('win')
|
||||
? '\r\n'
|
||||
: '\n';
|
||||
|
||||
/**
|
||||
* This function executes the gradle projectReportAll task and returns the output as an array of lines.
|
||||
@ -21,8 +12,6 @@ export async function getProjectReportLines(
|
||||
gradlewFile: string
|
||||
): Promise<string[]> {
|
||||
let projectReportBuffer: Buffer;
|
||||
|
||||
// Attempt to run projectReport or projectReportAll task, regardless of build.gradle or build.gradle.kts location
|
||||
try {
|
||||
projectReportBuffer = await execGradleAsync(gradlewFile, [
|
||||
'projectReportAll',
|
||||
849
packages/gradle/src/plugin/__snapshots__/nodes.spec.ts.snap
Normal file
849
packages/gradle/src/plugin/__snapshots__/nodes.spec.ts.snap
Normal file
@ -0,0 +1,849 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`@nx/gradle/plugin/nodes should create nodes based on gradle 1`] = `
|
||||
[
|
||||
[
|
||||
"proj/build.gradle",
|
||||
{
|
||||
"externalNodes": {},
|
||||
"projects": {
|
||||
"proj": {
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"help": [
|
||||
"buildEnvironment",
|
||||
],
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"name": "gradle-tutorial",
|
||||
"root": "proj",
|
||||
"targets": {
|
||||
"buildEnvironment": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :buildEnvironment",
|
||||
"metadata": {
|
||||
"description": "Displays all buildscript dependencies declared in root project 'gradle-tutorial'.",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`@nx/gradle/plugin/nodes should create nodes based on gradle for nested project root 1`] = `
|
||||
[
|
||||
[
|
||||
"nested/nested/proj/build.gradle",
|
||||
{
|
||||
"externalNodes": {},
|
||||
"projects": {
|
||||
"nested/nested/proj": {
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"help": [
|
||||
"buildEnvironment",
|
||||
],
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"name": "my-composite",
|
||||
"root": "nested/nested/proj",
|
||||
"targets": {
|
||||
"buildEnvironment": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :buildEnvironment",
|
||||
"metadata": {
|
||||
"description": "Displays all buildscript dependencies declared in root project 'my-composite'.",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "nested/nested/proj",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`@nx/gradle/plugin/nodes should create nodes with atomized tests targets based on gradle if ciTargetName is specified 1`] = `
|
||||
[
|
||||
[
|
||||
"proj/application/build.gradle",
|
||||
{
|
||||
"externalNodes": {},
|
||||
"projects": {
|
||||
"proj/application": {
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"verification": [
|
||||
"ci",
|
||||
],
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"name": "application",
|
||||
"root": "proj/application",
|
||||
"targets": {
|
||||
"ci": {
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest10",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest7",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest6",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest3",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest2",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest9",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest5",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest4",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest8",
|
||||
},
|
||||
],
|
||||
"executor": "nx:noop",
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle Tests in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest10": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest10",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest2": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest2",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest3": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest3",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest4": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest4",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest5": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest5",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest6": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest6",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest7": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest7",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest8": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest8",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest9": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest9",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`@nx/gradle/plugin/nodes should not create nodes with atomized tests targets based on gradle if ciTargetName is not specified 1`] = `
|
||||
[
|
||||
[
|
||||
"proj/application/build.gradle",
|
||||
{
|
||||
"externalNodes": {},
|
||||
"projects": {
|
||||
"proj/application": {
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"verification": [
|
||||
"ci",
|
||||
],
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"name": "application",
|
||||
"root": "proj/application",
|
||||
"targets": {
|
||||
"ci": {
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest10",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest7",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest6",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest3",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest2",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest9",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest5",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest4",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "ci--DemoApplicationTest8",
|
||||
},
|
||||
],
|
||||
"executor": "nx:noop",
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle Tests in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest10": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest10",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest2": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest2",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest3": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest3",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest4": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest4",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest5": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest5",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest6": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest6",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest7": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest7",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest8": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest8",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
"ci--DemoApplicationTest9": {
|
||||
"cache": true,
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest9",
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java in CI",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "proj",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
`;
|
||||
@ -2,94 +2,71 @@ import {
|
||||
CreateDependencies,
|
||||
CreateDependenciesContext,
|
||||
DependencyType,
|
||||
FileMap,
|
||||
RawProjectGraphDependency,
|
||||
logger,
|
||||
normalizePath,
|
||||
StaticDependency,
|
||||
validateDependency,
|
||||
workspaceRoot,
|
||||
} from '@nx/devkit';
|
||||
import { basename, dirname } from 'node:path';
|
||||
import { relative } from 'node:path';
|
||||
|
||||
import { getCurrentGradleReport } from '../utils/get-gradle-report';
|
||||
import { GRADLE_BUILD_FILES } from '../utils/split-config-files';
|
||||
import {
|
||||
getCurrentProjectGraphReport,
|
||||
populateProjectGraph,
|
||||
} from './utils/get-project-graph-from-gradle-plugin';
|
||||
import { GradlePluginOptions } from './utils/gradle-plugin-options';
|
||||
import { GRALDEW_FILES, splitConfigFiles } from '../utils/split-config-files';
|
||||
import { globWithWorkspaceContext } from 'nx/src/utils/workspace-context';
|
||||
|
||||
export const createDependencies: CreateDependencies = async (
|
||||
_,
|
||||
export const createDependencies: CreateDependencies<
|
||||
GradlePluginOptions
|
||||
> = async (
|
||||
options: GradlePluginOptions,
|
||||
context: CreateDependenciesContext
|
||||
) => {
|
||||
const gradleFiles: string[] = findGradleFiles(context.filesToProcess);
|
||||
if (gradleFiles.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const gradleDependenciesStart = performance.mark('gradleDependencies:start');
|
||||
const {
|
||||
gradleFileToGradleProjectMap,
|
||||
gradleProjectNameToProjectRootMap,
|
||||
buildFileToDepsMap,
|
||||
gradleProjectToChildProjects,
|
||||
} = getCurrentGradleReport();
|
||||
const dependencies: Set<RawProjectGraphDependency> = new Set();
|
||||
|
||||
for (const gradleFile of gradleFiles) {
|
||||
const gradleProject = gradleFileToGradleProjectMap.get(gradleFile);
|
||||
const projectName = Object.values(context.projects).find(
|
||||
(project) => project.root === dirname(gradleFile)
|
||||
)?.name;
|
||||
const dependedProjects: Set<string> = buildFileToDepsMap.get(gradleFile);
|
||||
|
||||
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;
|
||||
if (targetProjectName) {
|
||||
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) {
|
||||
const dependency: RawProjectGraphDependency = {
|
||||
source: projectName as string,
|
||||
target: childProject,
|
||||
type: DependencyType.static,
|
||||
sourceFile: gradleFile,
|
||||
};
|
||||
validateDependency(dependency, context);
|
||||
dependencies.add(dependency);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const gradleDependenciesEnd = performance.mark('gradleDependencies:end');
|
||||
performance.measure(
|
||||
'gradleDependencies',
|
||||
gradleDependenciesStart.name,
|
||||
gradleDependenciesEnd.name
|
||||
const files = await globWithWorkspaceContext(
|
||||
workspaceRoot,
|
||||
Array.from(GRALDEW_FILES)
|
||||
);
|
||||
const { gradlewFiles } = splitConfigFiles(files);
|
||||
await populateProjectGraph(context.workspaceRoot, gradlewFiles, options);
|
||||
const { dependencies: dependenciesFromReport } =
|
||||
getCurrentProjectGraphReport();
|
||||
|
||||
return Array.from(dependencies);
|
||||
const dependencies: Array<StaticDependency> = [];
|
||||
dependenciesFromReport.forEach((dependencyFromPlugin: StaticDependency) => {
|
||||
try {
|
||||
const source =
|
||||
relative(workspaceRoot, dependencyFromPlugin.source) || '.';
|
||||
const sourceProjectName =
|
||||
Object.values(context.projects).find(
|
||||
(project) => source === project.root
|
||||
)?.name ?? dependencyFromPlugin.source;
|
||||
const target =
|
||||
relative(workspaceRoot, dependencyFromPlugin.target) || '.';
|
||||
const targetProjectName =
|
||||
Object.values(context.projects).find(
|
||||
(project) => target === project.root
|
||||
)?.name ?? dependencyFromPlugin.target;
|
||||
if (!sourceProjectName || !targetProjectName) {
|
||||
return;
|
||||
}
|
||||
const dependency: StaticDependency = {
|
||||
source: sourceProjectName,
|
||||
target: targetProjectName,
|
||||
type: DependencyType.static,
|
||||
sourceFile: normalizePath(
|
||||
relative(workspaceRoot, dependencyFromPlugin.sourceFile)
|
||||
),
|
||||
};
|
||||
validateDependency(dependency, context);
|
||||
dependencies.push(dependency);
|
||||
} catch {
|
||||
logger.warn(
|
||||
`Unable to parse dependency from gradle plugin: ${dependencyFromPlugin.source} -> ${dependencyFromPlugin.target}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return dependencies;
|
||||
};
|
||||
|
||||
function findGradleFiles(fileMap: FileMap): string[] {
|
||||
const gradleFiles: string[] = [];
|
||||
|
||||
for (const [_, files] of Object.entries(fileMap.projectFileMap)) {
|
||||
for (const file of files) {
|
||||
if (GRADLE_BUILD_FILES.has(basename(file.file))) {
|
||||
gradleFiles.push(file.file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gradleFiles;
|
||||
}
|
||||
|
||||
@ -1,20 +1,22 @@
|
||||
import { CreateNodesContext } from '@nx/devkit';
|
||||
|
||||
import { CreateNodesContext, readJsonFile } from '@nx/devkit';
|
||||
import { join } from 'path';
|
||||
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';
|
||||
import { type GradleReport } from '../utils/get-gradle-report';
|
||||
import { type ProjectGraphReport } from './utils/get-project-graph-from-gradle-plugin';
|
||||
|
||||
let gradleReport: GradleReport;
|
||||
jest.mock('../utils/get-gradle-report', () => {
|
||||
let gradleReport: ProjectGraphReport;
|
||||
jest.mock('./utils/get-project-graph-from-gradle-plugin', () => {
|
||||
return {
|
||||
GRADLE_BUILD_FILES: new Set(['build.gradle', 'build.gradle.kts']),
|
||||
populateGradleReport: jest.fn().mockImplementation(() => void 0),
|
||||
getCurrentGradleReport: jest.fn().mockImplementation(() => gradleReport),
|
||||
populateProjectGraph: jest.fn().mockImplementation(() => void 0),
|
||||
getCurrentProjectGraphReport: jest
|
||||
.fn()
|
||||
.mockImplementation(() => gradleReport),
|
||||
};
|
||||
});
|
||||
|
||||
import { createNodesV2 } from './nodes';
|
||||
|
||||
describe('@nx/gradle/plugin', () => {
|
||||
describe('@nx/gradle/plugin/nodes', () => {
|
||||
let createNodesFunction = createNodesV2[1];
|
||||
let context: CreateNodesContext;
|
||||
let tempFs: TempFs;
|
||||
@ -22,32 +24,9 @@ describe('@nx/gradle/plugin', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
tempFs = new TempFs('test');
|
||||
gradleReport = {
|
||||
gradleFileToGradleProjectMap: new Map<string, string>([
|
||||
['proj/build.gradle', 'proj'],
|
||||
]),
|
||||
buildFileToDepsMap: new Map<string, Set<string>>(),
|
||||
gradleFileToOutputDirsMap: new Map<string, Map<string, string>>([
|
||||
['proj/build.gradle', new Map([['build', 'build']])],
|
||||
]),
|
||||
gradleProjectToTasksMap: new Map<string, Set<string>>([
|
||||
['proj', new Set(['test'])],
|
||||
]),
|
||||
gradleProjectToTasksTypeMap: new Map<string, Map<string, string>>([
|
||||
[
|
||||
'proj',
|
||||
new Map([
|
||||
['test', 'Verification'],
|
||||
['build', 'Build'],
|
||||
]),
|
||||
],
|
||||
]),
|
||||
gradleProjectToProjectName: new Map<string, string>([['proj', 'proj']]),
|
||||
gradleProjectNameToProjectRootMap: new Map<string, string>([
|
||||
['proj', 'proj'],
|
||||
]),
|
||||
gradleProjectToChildProjects: new Map<string, string[]>(),
|
||||
};
|
||||
gradleReport = readJsonFile(
|
||||
join(__dirname, 'utils/__mocks__/gradle_tutorial.json')
|
||||
);
|
||||
cwd = process.cwd();
|
||||
process.chdir(tempFs.tempDir);
|
||||
context = {
|
||||
@ -81,190 +60,13 @@ describe('@nx/gradle/plugin', () => {
|
||||
context
|
||||
);
|
||||
|
||||
expect(results).toMatchInlineSnapshot(`
|
||||
[
|
||||
[
|
||||
"proj/build.gradle",
|
||||
{
|
||||
"projects": {
|
||||
"proj": {
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"Verification": [
|
||||
"test",
|
||||
],
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"name": "proj",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"test": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:test",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('should create nodes include subprojects tasks', async () => {
|
||||
const results = await createNodesFunction(
|
||||
['proj/build.gradle'],
|
||||
{
|
||||
buildTargetName: 'build',
|
||||
includeSubprojectsTasks: true,
|
||||
},
|
||||
context
|
||||
);
|
||||
|
||||
expect(results).toMatchInlineSnapshot(`
|
||||
[
|
||||
[
|
||||
"proj/build.gradle",
|
||||
{
|
||||
"projects": {
|
||||
"proj": {
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"Build": [
|
||||
"build",
|
||||
],
|
||||
"Verification": [
|
||||
"test",
|
||||
],
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"name": "proj",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"build": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:build",
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
"classes",
|
||||
"test",
|
||||
],
|
||||
"inputs": [
|
||||
"production",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:build",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
"outputs": [
|
||||
"build",
|
||||
],
|
||||
},
|
||||
"test": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:test",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
`);
|
||||
expect(results).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should create nodes based on gradle for nested project root', async () => {
|
||||
gradleReport = {
|
||||
gradleFileToGradleProjectMap: new Map<string, string>([
|
||||
['nested/nested/proj/build.gradle', 'proj'],
|
||||
]),
|
||||
buildFileToDepsMap: new Map<string, Set<string>>(),
|
||||
gradleFileToOutputDirsMap: new Map<string, Map<string, string>>([
|
||||
['nested/nested/proj/build.gradle', new Map([['build', 'build']])],
|
||||
]),
|
||||
gradleProjectToTasksMap: new Map<string, Set<string>>([
|
||||
['proj', new Set(['test'])],
|
||||
]),
|
||||
gradleProjectToTasksTypeMap: new Map<string, Map<string, string>>([
|
||||
['proj', new Map([['test', 'Verification']])],
|
||||
]),
|
||||
gradleProjectToProjectName: new Map<string, string>([['proj', 'proj']]),
|
||||
gradleProjectNameToProjectRootMap: new Map<string, string>([
|
||||
['proj', 'proj'],
|
||||
]),
|
||||
gradleProjectToChildProjects: new Map<string, string[]>(),
|
||||
};
|
||||
gradleReport = readJsonFile(
|
||||
join(__dirname, '/utils/__mocks__/gradle_composite.json')
|
||||
);
|
||||
await tempFs.createFiles({
|
||||
'nested/nested/proj/build.gradle': ``,
|
||||
});
|
||||
@ -277,112 +79,12 @@ describe('@nx/gradle/plugin', () => {
|
||||
context
|
||||
);
|
||||
|
||||
expect(results).toMatchInlineSnapshot(`
|
||||
[
|
||||
[
|
||||
"nested/nested/proj/build.gradle",
|
||||
{
|
||||
"projects": {
|
||||
"nested/nested/proj": {
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"Verification": [
|
||||
"test",
|
||||
],
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"name": "proj",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"test": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:test",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
`);
|
||||
expect(results).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('with atomized tests targets', () => {
|
||||
beforeEach(async () => {
|
||||
gradleReport = {
|
||||
gradleFileToGradleProjectMap: new Map<string, string>([
|
||||
['nested/nested/proj/build.gradle', 'proj'],
|
||||
]),
|
||||
buildFileToDepsMap: new Map<string, Set<string>>(),
|
||||
gradleFileToOutputDirsMap: new Map<string, Map<string, string>>([
|
||||
['nested/nested/proj/build.gradle', new Map([['build', 'build']])],
|
||||
]),
|
||||
gradleProjectToTasksMap: new Map<string, Set<string>>([
|
||||
['proj', new Set(['test'])],
|
||||
]),
|
||||
gradleProjectToTasksTypeMap: new Map<string, Map<string, string>>([
|
||||
['proj', new Map([['test', 'Test']])],
|
||||
]),
|
||||
gradleProjectToProjectName: new Map<string, string>([['proj', 'proj']]),
|
||||
gradleProjectNameToProjectRootMap: new Map<string, string>([
|
||||
['proj', 'proj'],
|
||||
]),
|
||||
gradleProjectToChildProjects: new Map<string, string[]>(),
|
||||
};
|
||||
await tempFs.createFiles({
|
||||
'nested/nested/proj/build.gradle': ``,
|
||||
});
|
||||
await tempFs.createFiles({
|
||||
'proj/src/test/java/test/rootTest.java': ``,
|
||||
});
|
||||
await tempFs.createFiles({
|
||||
'nested/nested/proj/src/test/java/test/aTest.java': ``,
|
||||
});
|
||||
await tempFs.createFiles({
|
||||
'nested/nested/proj/src/test/java/test/bTest.java': ``,
|
||||
});
|
||||
await tempFs.createFiles({
|
||||
'nested/nested/proj/src/test/java/test/cTests.java': ``,
|
||||
});
|
||||
});
|
||||
|
||||
it('should create nodes with atomized tests targets based on gradle for nested project root', async () => {
|
||||
it('should create nodes with atomized tests targets based on gradle if ciTargetName is specified', async () => {
|
||||
const results = await createNodesFunction(
|
||||
[
|
||||
'nested/nested/proj/build.gradle',
|
||||
'proj/src/test/java/test/rootTest.java',
|
||||
'nested/nested/proj/src/test/java/test/aTest.java',
|
||||
'nested/nested/proj/src/test/java/test/bTest.java',
|
||||
'nested/nested/proj/src/test/java/test/cTests.java',
|
||||
],
|
||||
['proj/application/build.gradle'],
|
||||
{
|
||||
buildTargetName: 'build',
|
||||
ciTargetName: 'test-ci',
|
||||
@ -390,198 +92,17 @@ describe('@nx/gradle/plugin', () => {
|
||||
context
|
||||
);
|
||||
|
||||
expect(results).toMatchInlineSnapshot(`
|
||||
[
|
||||
[
|
||||
"nested/nested/proj/build.gradle",
|
||||
{
|
||||
"projects": {
|
||||
"nested/nested/proj": {
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"Test": [
|
||||
"test-ci--aTest",
|
||||
"test-ci--bTest",
|
||||
"test-ci--cTests",
|
||||
"test-ci",
|
||||
"test",
|
||||
],
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"name": "proj",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"test": {
|
||||
"cache": false,
|
||||
"command": "./gradlew proj:test",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
"test-ci": {
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "test-ci--aTest",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "test-ci--bTest",
|
||||
},
|
||||
{
|
||||
"params": "forward",
|
||||
"projects": "self",
|
||||
"target": "test-ci--cTests",
|
||||
},
|
||||
],
|
||||
"executor": "nx:noop",
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle Tests in CI",
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"nonAtomizedTarget": "test",
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
},
|
||||
"test-ci--aTest": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:test --tests aTest",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test nested/nested/proj/src/test/java/test/aTest.java in CI",
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
"test-ci--bTest": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:test --tests bTest",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test nested/nested/proj/src/test/java/test/bTest.java in CI",
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
"test-ci--cTests": {
|
||||
"cache": true,
|
||||
"command": "./gradlew proj:test --tests cTests",
|
||||
"dependsOn": [
|
||||
"testClasses",
|
||||
],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test nested/nested/proj/src/test/java/test/cTests.java in CI",
|
||||
"help": {
|
||||
"command": "./gradlew help --task proj:test",
|
||||
"example": {
|
||||
"options": {
|
||||
"args": [
|
||||
"--rerun",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"gradle",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": ".",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
`);
|
||||
expect(results).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should not create nodes with atomized tests targets based on gradle if ciTargetName is not specified', async () => {
|
||||
const results = await createNodesFunction(
|
||||
['proj/application/build.gradle'],
|
||||
{
|
||||
buildTargetName: 'build',
|
||||
},
|
||||
context
|
||||
);
|
||||
expect(results).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,67 +1,36 @@
|
||||
import {
|
||||
CreateNodes,
|
||||
CreateNodesV2,
|
||||
CreateNodesContext,
|
||||
ProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
createNodesFromFiles,
|
||||
readJsonFile,
|
||||
writeJsonFile,
|
||||
CreateNodesFunction,
|
||||
logger,
|
||||
workspaceRoot,
|
||||
ProjectGraphExternalNode,
|
||||
} from '@nx/devkit';
|
||||
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { basename, dirname, join } from 'node:path';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { workspaceDataDirectory } from 'nx/src/utils/cache-directory';
|
||||
import { findProjectForPath } from 'nx/src/devkit-internals';
|
||||
|
||||
import {
|
||||
populateGradleReport,
|
||||
getCurrentGradleReport,
|
||||
GradleReport,
|
||||
} from '../utils/get-gradle-report';
|
||||
import { hashObject } from 'nx/src/hasher/file-hasher';
|
||||
import {
|
||||
gradleConfigAndTestGlob,
|
||||
gradleConfigGlob,
|
||||
splitConfigFiles,
|
||||
} from '../utils/split-config-files';
|
||||
import { getGradleExecFile, findGraldewFile } from '../utils/exec-gradle';
|
||||
|
||||
const cacheableTaskType = new Set(['Build', 'Verification']);
|
||||
const dependsOnMap = {
|
||||
build: ['^build', 'classes', 'test'],
|
||||
testClasses: ['classes'],
|
||||
test: ['testClasses'],
|
||||
classes: ['^classes'],
|
||||
};
|
||||
|
||||
interface GradleTask {
|
||||
type: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface GradlePluginOptions {
|
||||
includeSubprojectsTasks?: boolean; // default is false, show all gradle tasks in the project
|
||||
ciTargetName?: string;
|
||||
testTargetName?: string;
|
||||
classesTargetName?: string;
|
||||
buildTargetName?: string;
|
||||
[taskTargetName: string]: string | undefined | boolean;
|
||||
}
|
||||
|
||||
function normalizeOptions(options: GradlePluginOptions): GradlePluginOptions {
|
||||
options ??= {};
|
||||
options.testTargetName ??= 'test';
|
||||
options.classesTargetName ??= 'classes';
|
||||
options.buildTargetName ??= 'build';
|
||||
return options;
|
||||
}
|
||||
import {
|
||||
getCurrentProjectGraphReport,
|
||||
populateProjectGraph,
|
||||
} from './utils/get-project-graph-from-gradle-plugin';
|
||||
import {
|
||||
GradlePluginOptions,
|
||||
normalizeOptions,
|
||||
} from './utils/gradle-plugin-options';
|
||||
|
||||
type GradleTargets = Record<string, Partial<ProjectConfiguration>>;
|
||||
|
||||
function readTargetsCache(cachePath: string): GradleTargets {
|
||||
function readProjectsCache(cachePath: string): GradleTargets {
|
||||
return existsSync(cachePath) ? readJsonFile(cachePath) : {};
|
||||
}
|
||||
|
||||
@ -72,47 +41,39 @@ export function writeTargetsToCache(cachePath: string, results: GradleTargets) {
|
||||
export const createNodesV2: CreateNodesV2<GradlePluginOptions> = [
|
||||
gradleConfigAndTestGlob,
|
||||
async (files, options, context) => {
|
||||
const { buildFiles, projectRoots, gradlewFiles, testFiles } =
|
||||
splitConfigFiles(files);
|
||||
const { buildFiles, gradlewFiles } = splitConfigFiles(files);
|
||||
const optionsHash = hashObject(options);
|
||||
const cachePath = join(
|
||||
workspaceDataDirectory,
|
||||
`gradle-${optionsHash}.hash`
|
||||
);
|
||||
const targetsCache = readTargetsCache(cachePath);
|
||||
const projectsCache = readProjectsCache(cachePath);
|
||||
|
||||
await populateGradleReport(
|
||||
await populateProjectGraph(
|
||||
context.workspaceRoot,
|
||||
gradlewFiles.map((f) => join(context.workspaceRoot, f))
|
||||
);
|
||||
const gradleReport = getCurrentGradleReport();
|
||||
const gradleProjectRootToTestFilesMap = getGradleProjectRootToTestFilesMap(
|
||||
testFiles,
|
||||
projectRoots
|
||||
gradlewFiles.map((f) => join(context.workspaceRoot, f)),
|
||||
options
|
||||
);
|
||||
const { nodes, externalNodes } = getCurrentProjectGraphReport();
|
||||
|
||||
try {
|
||||
return createNodesFromFiles(
|
||||
makeCreateNodesForGradleConfigFile(
|
||||
gradleReport,
|
||||
targetsCache,
|
||||
gradleProjectRootToTestFilesMap
|
||||
),
|
||||
makeCreateNodesForGradleConfigFile(nodes, projectsCache, externalNodes),
|
||||
buildFiles,
|
||||
options,
|
||||
context
|
||||
);
|
||||
} finally {
|
||||
writeTargetsToCache(cachePath, targetsCache);
|
||||
writeTargetsToCache(cachePath, projectsCache);
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
export const makeCreateNodesForGradleConfigFile =
|
||||
(
|
||||
gradleReport: GradleReport,
|
||||
targetsCache: GradleTargets = {},
|
||||
gradleProjectRootToTestFilesMap: Record<string, string[]> = {}
|
||||
projects: Record<string, Partial<ProjectConfiguration>>,
|
||||
projectsCache: GradleTargets = {},
|
||||
externalNodes: Record<string, ProjectGraphExternalNode> = {}
|
||||
): CreateNodesFunction =>
|
||||
async (
|
||||
gradleFilePath,
|
||||
@ -127,309 +88,18 @@ export const makeCreateNodesForGradleConfigFile =
|
||||
options ?? {},
|
||||
context
|
||||
);
|
||||
targetsCache[hash] ??= await createGradleProject(
|
||||
gradleReport,
|
||||
gradleFilePath,
|
||||
options,
|
||||
context,
|
||||
gradleProjectRootToTestFilesMap[projectRoot]
|
||||
);
|
||||
const project = targetsCache[hash];
|
||||
projectsCache[hash] ??=
|
||||
projects[projectRoot] ?? projects[join(workspaceRoot, projectRoot)];
|
||||
const project = projectsCache[hash];
|
||||
if (!project) {
|
||||
return {};
|
||||
}
|
||||
project.root = projectRoot;
|
||||
|
||||
return {
|
||||
projects: {
|
||||
[projectRoot]: project,
|
||||
},
|
||||
externalNodes: externalNodes,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@deprecated This is replaced with {@link createNodesV2}. Update your plugin to export its own `createNodesV2` function that wraps this one instead.
|
||||
This function will change to the v2 function in Nx 20.
|
||||
*/
|
||||
export const createNodes: CreateNodes<GradlePluginOptions> = [
|
||||
gradleConfigGlob,
|
||||
async (buildFile, options, context) => {
|
||||
logger.warn(
|
||||
'`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.'
|
||||
);
|
||||
const { gradlewFiles } = splitConfigFiles(context.configFiles);
|
||||
await populateGradleReport(context.workspaceRoot, gradlewFiles);
|
||||
const gradleReport = getCurrentGradleReport();
|
||||
const internalCreateNodes =
|
||||
makeCreateNodesForGradleConfigFile(gradleReport);
|
||||
return await internalCreateNodes(buildFile, options, context);
|
||||
},
|
||||
];
|
||||
|
||||
async function createGradleProject(
|
||||
gradleReport: GradleReport,
|
||||
gradleFilePath: string,
|
||||
options: GradlePluginOptions | undefined,
|
||||
context: CreateNodesContext,
|
||||
testFiles = []
|
||||
) {
|
||||
try {
|
||||
const {
|
||||
gradleProjectToTasksTypeMap,
|
||||
gradleProjectToTasksMap,
|
||||
gradleFileToOutputDirsMap,
|
||||
gradleFileToGradleProjectMap,
|
||||
gradleProjectToProjectName,
|
||||
} = gradleReport;
|
||||
|
||||
const gradleProject = gradleFileToGradleProjectMap.get(
|
||||
gradleFilePath
|
||||
) as string;
|
||||
const projectName = gradleProjectToProjectName.get(gradleProject);
|
||||
if (!projectName) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tasksTypeMap: Map<string, string> = gradleProjectToTasksTypeMap.get(
|
||||
gradleProject
|
||||
) as Map<string, string>;
|
||||
const tasksSet = gradleProjectToTasksMap.get(gradleProject) as Set<string>;
|
||||
let tasks: GradleTask[] = [];
|
||||
tasksSet.forEach((taskName) => {
|
||||
tasks.push({
|
||||
type: tasksTypeMap?.get(taskName) as string,
|
||||
name: taskName,
|
||||
});
|
||||
});
|
||||
if (options.includeSubprojectsTasks) {
|
||||
tasksTypeMap.forEach((taskType, taskName) => {
|
||||
if (!tasksSet.has(taskName)) {
|
||||
tasks.push({
|
||||
type: taskType,
|
||||
name: taskName,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const outputDirs = gradleFileToOutputDirsMap.get(gradleFilePath) as Map<
|
||||
string,
|
||||
string
|
||||
>;
|
||||
|
||||
const { targets, targetGroups } = await createGradleTargets(
|
||||
tasks,
|
||||
options,
|
||||
context,
|
||||
outputDirs,
|
||||
gradleProject,
|
||||
gradleFilePath,
|
||||
testFiles
|
||||
);
|
||||
const project: Partial<ProjectConfiguration> = {
|
||||
name: projectName,
|
||||
projectType: 'application',
|
||||
targets,
|
||||
metadata: {
|
||||
targetGroups,
|
||||
technologies: ['gradle'],
|
||||
},
|
||||
};
|
||||
|
||||
return project;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async function createGradleTargets(
|
||||
tasks: GradleTask[],
|
||||
options: GradlePluginOptions | undefined,
|
||||
context: CreateNodesContext,
|
||||
outputDirs: Map<string, string>,
|
||||
gradleProject: string,
|
||||
gradleBuildFilePath: string,
|
||||
testFiles: string[] = []
|
||||
): Promise<{
|
||||
targetGroups: Record<string, string[]>;
|
||||
targets: Record<string, TargetConfiguration>;
|
||||
}> {
|
||||
const inputsMap = createInputsMap(context);
|
||||
const gradlewFileDirectory = dirname(
|
||||
findGraldewFile(gradleBuildFilePath, context.workspaceRoot)
|
||||
);
|
||||
|
||||
const targets: Record<string, TargetConfiguration> = {};
|
||||
const targetGroups: Record<string, string[]> = {};
|
||||
for (const task of tasks) {
|
||||
const targetName = options?.[`${task.name}TargetName`] ?? task.name;
|
||||
|
||||
let outputs = [outputDirs.get(task.name)].filter(Boolean);
|
||||
if (task.name === 'test') {
|
||||
outputs = [
|
||||
outputDirs.get('testReport'),
|
||||
outputDirs.get('testResults'),
|
||||
].filter(Boolean);
|
||||
getTestCiTargets(
|
||||
testFiles,
|
||||
gradleProject,
|
||||
targetName as string,
|
||||
options.ciTargetName,
|
||||
inputsMap['test'],
|
||||
outputs,
|
||||
task.type,
|
||||
targets,
|
||||
targetGroups,
|
||||
gradlewFileDirectory
|
||||
);
|
||||
}
|
||||
|
||||
const taskCommandToRun = `${gradleProject ? gradleProject + ':' : ''}${
|
||||
task.name
|
||||
}`;
|
||||
|
||||
targets[targetName as string] = {
|
||||
command: `${getGradleExecFile()} ${taskCommandToRun}`,
|
||||
options: {
|
||||
cwd: gradlewFileDirectory,
|
||||
},
|
||||
cache: cacheableTaskType.has(task.type),
|
||||
inputs: inputsMap[task.name],
|
||||
dependsOn: dependsOnMap[task.name],
|
||||
metadata: {
|
||||
technologies: ['gradle'],
|
||||
help: {
|
||||
command: `${getGradleExecFile()} help --task ${taskCommandToRun}`,
|
||||
example: {
|
||||
options: {
|
||||
args: ['--rerun'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
...(outputs && outputs.length ? { outputs } : {}),
|
||||
};
|
||||
|
||||
if (task.type) {
|
||||
if (!targetGroups[task.type]) {
|
||||
targetGroups[task.type] = [];
|
||||
}
|
||||
targetGroups[task.type].push(targetName as string);
|
||||
}
|
||||
}
|
||||
return { targetGroups, targets };
|
||||
}
|
||||
|
||||
function createInputsMap(
|
||||
context: CreateNodesContext
|
||||
): Record<string, TargetConfiguration['inputs']> {
|
||||
const namedInputs = context.nxJsonConfiguration.namedInputs;
|
||||
return {
|
||||
build: namedInputs?.production
|
||||
? ['production', '^production']
|
||||
: ['default', '^default'],
|
||||
test: ['default', namedInputs?.production ? '^production' : '^default'],
|
||||
classes: namedInputs?.production
|
||||
? ['production', '^production']
|
||||
: ['default', '^default'],
|
||||
};
|
||||
}
|
||||
|
||||
function getTestCiTargets(
|
||||
testFiles: string[],
|
||||
gradleProject: string,
|
||||
testTargetName: string,
|
||||
ciTargetName: string,
|
||||
inputs: TargetConfiguration['inputs'],
|
||||
outputs: string[],
|
||||
targetGroupName: string,
|
||||
targets: Record<string, TargetConfiguration>,
|
||||
targetGroups: Record<string, string[]>,
|
||||
gradlewFileDirectory: string
|
||||
): void {
|
||||
if (!testFiles || testFiles.length === 0 || !ciTargetName) {
|
||||
return;
|
||||
}
|
||||
const taskCommandToRun = `${gradleProject ? gradleProject + ':' : ''}test`;
|
||||
|
||||
if (!targetGroups[targetGroupName]) {
|
||||
targetGroups[targetGroupName] = [];
|
||||
}
|
||||
|
||||
const dependsOn: TargetConfiguration['dependsOn'] = [];
|
||||
testFiles.forEach((testFile) => {
|
||||
const testName = basename(testFile).split('.')[0];
|
||||
const targetName = ciTargetName + '--' + testName;
|
||||
|
||||
targets[targetName] = {
|
||||
command: `${getGradleExecFile()} ${taskCommandToRun} --tests ${testName}`,
|
||||
options: {
|
||||
cwd: gradlewFileDirectory,
|
||||
},
|
||||
cache: true,
|
||||
inputs,
|
||||
dependsOn: dependsOnMap['test'],
|
||||
metadata: {
|
||||
technologies: ['gradle'],
|
||||
description: `Runs Gradle test ${testFile} in CI`,
|
||||
help: {
|
||||
command: `${getGradleExecFile()} help --task ${taskCommandToRun}`,
|
||||
example: {
|
||||
options: {
|
||||
args: ['--rerun'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
...(outputs && outputs.length > 0 ? { outputs } : {}),
|
||||
};
|
||||
targetGroups[targetGroupName].push(targetName);
|
||||
dependsOn.push({
|
||||
target: targetName,
|
||||
projects: 'self',
|
||||
params: 'forward',
|
||||
});
|
||||
});
|
||||
|
||||
targets[ciTargetName] = {
|
||||
executor: 'nx:noop',
|
||||
cache: true,
|
||||
inputs,
|
||||
dependsOn: dependsOn,
|
||||
...(outputs && outputs.length > 0 ? { outputs } : {}),
|
||||
metadata: {
|
||||
technologies: ['gradle'],
|
||||
description: 'Runs Gradle Tests in CI',
|
||||
nonAtomizedTarget: testTargetName,
|
||||
help: {
|
||||
command: `${getGradleExecFile()} help --task ${taskCommandToRun}`,
|
||||
example: {
|
||||
options: {
|
||||
args: ['--rerun'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
targetGroups[targetGroupName].push(ciTargetName);
|
||||
}
|
||||
|
||||
function getGradleProjectRootToTestFilesMap(
|
||||
testFiles: string[],
|
||||
projectRoots: string[]
|
||||
): Record<string, string[]> | undefined {
|
||||
if (testFiles.length === 0 || projectRoots.length === 0) {
|
||||
return;
|
||||
}
|
||||
const roots = new Map(projectRoots.map((root) => [root, root]));
|
||||
const testFilesToGradleProjectMap: Record<string, string[]> = {};
|
||||
testFiles.forEach((testFile) => {
|
||||
const projectRoot = findProjectForPath(testFile, roots);
|
||||
if (projectRoot) {
|
||||
if (!testFilesToGradleProjectMap[projectRoot]) {
|
||||
testFilesToGradleProjectMap[projectRoot] = [];
|
||||
}
|
||||
testFilesToGradleProjectMap[projectRoot].push(testFile);
|
||||
}
|
||||
});
|
||||
return testFilesToGradleProjectMap;
|
||||
}
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nested/nested/proj": {
|
||||
"targets": {
|
||||
"buildEnvironment": {
|
||||
"cache": true,
|
||||
"metadata": {
|
||||
"description": "Displays all buildscript dependencies declared in root project \u0027my-composite\u0027.",
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"command": "./gradlew :buildEnvironment",
|
||||
"options": {
|
||||
"cwd": "nested/nested/proj"
|
||||
}
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"help": ["buildEnvironment"]
|
||||
},
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"name": "my-composite"
|
||||
}
|
||||
},
|
||||
"dependencies": [
|
||||
{
|
||||
"source": "nested/nested/proj",
|
||||
"target": "projectRoot/my-app",
|
||||
"sourceFile": "projectRoot/build.gradle.kts"
|
||||
},
|
||||
{
|
||||
"source": "nested/nested/proj",
|
||||
"target": "projectRoot/my-utils",
|
||||
"sourceFile": "projectRoot/build.gradle.kts"
|
||||
}
|
||||
]
|
||||
}
|
||||
590
packages/gradle/src/plugin/utils/__mocks__/gradle_nx_list.json
Normal file
590
packages/gradle/src/plugin/utils/__mocks__/gradle_nx_list.json
Normal file
@ -0,0 +1,590 @@
|
||||
{
|
||||
"targets": {
|
||||
"assemble": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"dependsOn": ["list:jar"],
|
||||
"command": "./gradlew :list:assemble",
|
||||
"metadata": {
|
||||
"description": "Assembles the outputs of this project.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:assemble" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"build": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"dependsOn": ["list:check", "list:assemble"],
|
||||
"command": "./gradlew :list:build",
|
||||
"metadata": {
|
||||
"description": "Assembles and tests this project.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:build" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"buildDependents": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:buildDependents",
|
||||
"metadata": {
|
||||
"description": "Assembles and tests this project and all projects that depend on it.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:buildDependents" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"buildEnvironment": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:buildEnvironment",
|
||||
"metadata": {
|
||||
"description": "Displays all buildscript dependencies declared in project \u0027:list\u0027.",
|
||||
"technologies": ["gradle"],
|
||||
"help": {
|
||||
"command": "./gradlew help --task :list:buildEnvironment"
|
||||
}
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"buildNeeded": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"dependsOn": ["list:build"],
|
||||
"command": "./gradlew :list:buildNeeded",
|
||||
"metadata": {
|
||||
"description": "Assembles and tests this project and all projects it depends on.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:buildNeeded" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"check": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"dependsOn": ["list:test"],
|
||||
"command": "./gradlew :list:check",
|
||||
"metadata": {
|
||||
"description": "Runs all checks.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:check" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"classes": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"dependsOn": ["list:compileJava", "list:processResources"],
|
||||
"command": "./gradlew :list:classes",
|
||||
"metadata": {
|
||||
"description": "Assembles main classes.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:classes" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"clean": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:clean",
|
||||
"metadata": {
|
||||
"description": "Deletes the build directory.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:clean" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"compileJava": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"inputs": [
|
||||
"{projectRoot}/src/main/java/org/example/list/LinkedList.java"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/main",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/main",
|
||||
"{projectRoot}/build/generated/sources/headers/java/main",
|
||||
"{projectRoot}/build/tmp/compileJava/previous-compilation-data.bin"
|
||||
],
|
||||
"command": "./gradlew :list:compileJava",
|
||||
"metadata": {
|
||||
"description": "Compiles main Java source.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:compileJava" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"compileTestJava": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/org/example/list/LinkedListTest.java",
|
||||
"{projectRoot}/src/test/java/org/example/list/LinkedList2Test.java"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin"
|
||||
],
|
||||
"dependsOn": ["list:classes", "list:compileJava"],
|
||||
"command": "./gradlew :list:compileTestJava",
|
||||
"metadata": {
|
||||
"description": "Compiles test Java source.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:compileTestJava" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"ci--LinkedListTest": {
|
||||
"command": "./gradlew :list:test --tests LinkedListTest",
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test LinkedListTest in CI",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:test" }
|
||||
},
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/org/example/list/LinkedListTest.java"
|
||||
],
|
||||
"dependsOn": [
|
||||
"list:compileTestJava",
|
||||
"list:testClasses",
|
||||
"list:classes",
|
||||
"list:compileJava"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/test-results/test/binary",
|
||||
"{projectRoot}/build/reports/tests/test",
|
||||
"{projectRoot}/build/test-results/test"
|
||||
]
|
||||
},
|
||||
"ci--LinkedList2Test": {
|
||||
"command": "./gradlew :list:test --tests LinkedList2Test",
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test LinkedList2Test in CI",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:test" }
|
||||
},
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/org/example/list/LinkedList2Test.java"
|
||||
],
|
||||
"dependsOn": [
|
||||
"list:compileTestJava",
|
||||
"list:testClasses",
|
||||
"list:classes",
|
||||
"list:compileJava"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/test-results/test/binary",
|
||||
"{projectRoot}/build/reports/tests/test",
|
||||
"{projectRoot}/build/test-results/test"
|
||||
]
|
||||
},
|
||||
"ci": {
|
||||
"executor": "nx:noop",
|
||||
"metadata": {
|
||||
"description": "Runs Gradle Tests in CI",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:test" }
|
||||
},
|
||||
"dependsOn": [
|
||||
{
|
||||
"target": "ci--LinkedListTest",
|
||||
"projects": "self",
|
||||
"params": "forward"
|
||||
},
|
||||
{
|
||||
"target": "ci--LinkedList2Test",
|
||||
"projects": "self",
|
||||
"params": "forward"
|
||||
}
|
||||
],
|
||||
"cache": true,
|
||||
"parallelism": false
|
||||
},
|
||||
"components": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:components",
|
||||
"metadata": {
|
||||
"description": "Displays the components produced by project \u0027:list\u0027. [deprecated]",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:components" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"nxProjectGraph": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"dependsOn": ["list:nxProjectGraphLocal"],
|
||||
"command": "./gradlew :list:nxProjectGraph",
|
||||
"metadata": {
|
||||
"description": "Print nodes report for Nx",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:nxProjectGraph" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"createNodesLocal": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"outputs": ["{projectRoot}/build/nx/list.json"],
|
||||
"command": "./gradlew :list:nxProjectGraphLocal",
|
||||
"metadata": {
|
||||
"description": "Create nodes and dependencies for Nx",
|
||||
"technologies": ["gradle"],
|
||||
"help": {
|
||||
"command": "./gradlew help --task :list:nxProjectGraphLocal"
|
||||
}
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"dependencies": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:dependencies",
|
||||
"metadata": {
|
||||
"description": "Displays all dependencies declared in project \u0027:list\u0027.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:dependencies" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"dependencyInsight": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:dependencyInsight",
|
||||
"metadata": {
|
||||
"description": "Displays the insight into a specific dependency in project \u0027:list\u0027.",
|
||||
"technologies": ["gradle"],
|
||||
"help": {
|
||||
"command": "./gradlew help --task :list:dependencyInsight"
|
||||
}
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"dependencyReport": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"outputs": ["{projectRoot}/build/reports/project/dependencies.txt"],
|
||||
"command": "./gradlew :list:dependencyReport",
|
||||
"metadata": {
|
||||
"description": "Generates a report about your library dependencies.",
|
||||
"technologies": ["gradle"],
|
||||
"help": {
|
||||
"command": "./gradlew help --task :list:dependencyReport"
|
||||
}
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"dependentComponents": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:dependentComponents",
|
||||
"metadata": {
|
||||
"description": "Displays the dependent components of components in project \u0027:list\u0027. [deprecated]",
|
||||
"technologies": ["gradle"],
|
||||
"help": {
|
||||
"command": "./gradlew help --task :list:dependentComponents"
|
||||
}
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"help": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:help",
|
||||
"metadata": {
|
||||
"description": "Displays a help message.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:help" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"htmlDependencyReport": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"outputs": ["{projectRoot}/build/reports/project/dependencies"],
|
||||
"command": "./gradlew :list:htmlDependencyReport",
|
||||
"metadata": {
|
||||
"description": "Generates an HTML report about your library dependencies.",
|
||||
"technologies": ["gradle"],
|
||||
"help": {
|
||||
"command": "./gradlew help --task :list:htmlDependencyReport"
|
||||
}
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"jar": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"inputs": ["{projectRoot}/build/tmp/jar/MANIFEST.MF"],
|
||||
"outputs": ["{projectRoot}/build/libs/list.jar"],
|
||||
"dependsOn": ["list:classes", "list:compileJava"],
|
||||
"command": "./gradlew :list:jar",
|
||||
"metadata": {
|
||||
"description": "Assembles a jar archive containing the classes of the \u0027main\u0027 feature.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:jar" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"javaToolchains": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:javaToolchains",
|
||||
"metadata": {
|
||||
"description": "Displays the detected java toolchains.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:javaToolchains" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"javadoc": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"inputs": [
|
||||
"{projectRoot}/src/main/java/org/example/list/LinkedList.java"
|
||||
],
|
||||
"outputs": ["{projectRoot}/build/docs/javadoc"],
|
||||
"dependsOn": ["list:classes", "list:compileJava"],
|
||||
"command": "./gradlew :list:javadoc",
|
||||
"metadata": {
|
||||
"description": "Generates Javadoc API documentation for the \u0027main\u0027 feature.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:javadoc" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"kotlinDslAccessorsReport": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:kotlinDslAccessorsReport",
|
||||
"metadata": {
|
||||
"description": "Prints the Kotlin code for accessing the currently available project extensions and conventions.",
|
||||
"technologies": ["gradle"],
|
||||
"help": {
|
||||
"command": "./gradlew help --task :list:kotlinDslAccessorsReport"
|
||||
}
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"model": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:model",
|
||||
"metadata": {
|
||||
"description": "Displays the configuration model of project \u0027:list\u0027. [deprecated]",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:model" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"outgoingVariants": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:outgoingVariants",
|
||||
"metadata": {
|
||||
"description": "Displays the outgoing variants of project \u0027:list\u0027.",
|
||||
"technologies": ["gradle"],
|
||||
"help": {
|
||||
"command": "./gradlew help --task :list:outgoingVariants"
|
||||
}
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"processResources": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"outputs": ["{projectRoot}/build/resources/main"],
|
||||
"command": "./gradlew :list:processResources",
|
||||
"metadata": {
|
||||
"description": "Processes main resources.",
|
||||
"technologies": ["gradle"],
|
||||
"help": {
|
||||
"command": "./gradlew help --task :list:processResources"
|
||||
}
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"processTestResources": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"outputs": ["{projectRoot}/build/resources/test"],
|
||||
"command": "./gradlew :list:processTestResources",
|
||||
"metadata": {
|
||||
"description": "Processes test resources.",
|
||||
"technologies": ["gradle"],
|
||||
"help": {
|
||||
"command": "./gradlew help --task :list:processTestResources"
|
||||
}
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"projectReport": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"dependsOn": [
|
||||
"list:taskReport",
|
||||
"list:dependencyReport",
|
||||
"list:propertyReport",
|
||||
"list:htmlDependencyReport"
|
||||
],
|
||||
"command": "./gradlew :list:projectReport",
|
||||
"metadata": {
|
||||
"description": "Generates a report about your project.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:projectReport" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"projects": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:projects",
|
||||
"metadata": {
|
||||
"description": "Displays the sub-projects of project \u0027:list\u0027.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:projects" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"properties": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:properties",
|
||||
"metadata": {
|
||||
"description": "Displays the properties of project \u0027:list\u0027.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:properties" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"propertyReport": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"outputs": ["{projectRoot}/build/reports/project/properties.txt"],
|
||||
"command": "./gradlew :list:propertyReport",
|
||||
"metadata": {
|
||||
"description": "Generates a report about your properties.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:propertyReport" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"resolvableConfigurations": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:resolvableConfigurations",
|
||||
"metadata": {
|
||||
"description": "Displays the configurations that can be resolved in project \u0027:list\u0027.",
|
||||
"technologies": ["gradle"],
|
||||
"help": {
|
||||
"command": "./gradlew help --task :list:resolvableConfigurations"
|
||||
}
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"taskReport": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"outputs": ["{projectRoot}/build/reports/project/tasks.txt"],
|
||||
"command": "./gradlew :list:taskReport",
|
||||
"metadata": {
|
||||
"description": "Generates a report about your tasks.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:taskReport" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"tasks": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"command": "./gradlew :list:tasks",
|
||||
"metadata": {
|
||||
"description": "Displays the tasks runnable from project \u0027:list\u0027.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:tasks" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"test": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"outputs": [
|
||||
"{projectRoot}/build/test-results/test/binary",
|
||||
"{projectRoot}/build/reports/tests/test",
|
||||
"{projectRoot}/build/test-results/test"
|
||||
],
|
||||
"dependsOn": [
|
||||
"list:compileTestJava",
|
||||
"list:testClasses",
|
||||
"list:classes",
|
||||
"list:compileJava"
|
||||
],
|
||||
"command": "./gradlew :list:test",
|
||||
"metadata": {
|
||||
"description": "Runs the test suite.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:test" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
},
|
||||
"testClasses": {
|
||||
"cache": true,
|
||||
"parallelism": false,
|
||||
"dependsOn": ["list:processTestResources", "list:compileTestJava"],
|
||||
"command": "./gradlew :list:testClasses",
|
||||
"metadata": {
|
||||
"description": "Assembles test classes.",
|
||||
"technologies": ["gradle"],
|
||||
"help": { "command": "./gradlew help --task :list:testClasses" }
|
||||
},
|
||||
"options": { "cwd": "." }
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"build": [
|
||||
"assemble",
|
||||
"build",
|
||||
"buildDependents",
|
||||
"buildNeeded",
|
||||
"classes",
|
||||
"clean",
|
||||
"jar",
|
||||
"testClasses"
|
||||
],
|
||||
"help": [
|
||||
"buildEnvironment",
|
||||
"dependencies",
|
||||
"dependencyInsight",
|
||||
"help",
|
||||
"javaToolchains",
|
||||
"kotlinDslAccessorsReport",
|
||||
"outgoingVariants",
|
||||
"projects",
|
||||
"properties",
|
||||
"resolvableConfigurations",
|
||||
"tasks"
|
||||
],
|
||||
"verification": [
|
||||
"check",
|
||||
"ci--LinkedListTest",
|
||||
"ci--LinkedList2Test",
|
||||
"ci",
|
||||
"test"
|
||||
],
|
||||
"Nx Custom": ["createNodes", "createNodesLocal"],
|
||||
"documentation": ["javadoc"],
|
||||
"reporting": ["projectReport"]
|
||||
},
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"name": "list"
|
||||
}
|
||||
344
packages/gradle/src/plugin/utils/__mocks__/gradle_tutorial.json
Normal file
344
packages/gradle/src/plugin/utils/__mocks__/gradle_tutorial.json
Normal file
@ -0,0 +1,344 @@
|
||||
{
|
||||
"nodes": {
|
||||
"proj": {
|
||||
"targets": {
|
||||
"buildEnvironment": {
|
||||
"cache": true,
|
||||
"metadata": {
|
||||
"description": "Displays all buildscript dependencies declared in root project \u0027gradle-tutorial\u0027.",
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"command": "./gradlew :buildEnvironment",
|
||||
"options": { "cwd": "proj" }
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"help": ["buildEnvironment"]
|
||||
},
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"name": "gradle-tutorial"
|
||||
},
|
||||
"proj/application": {
|
||||
"targets": {
|
||||
"ci--DemoApplicationTest10": {
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin"
|
||||
],
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar"
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java in CI",
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest10",
|
||||
"options": { "cwd": "proj" }
|
||||
},
|
||||
"ci--DemoApplicationTest7": {
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin"
|
||||
],
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar"
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java in CI",
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest7",
|
||||
"options": { "cwd": "proj" }
|
||||
},
|
||||
"ci--DemoApplicationTest6": {
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin"
|
||||
],
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar"
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java in CI",
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest6",
|
||||
"options": { "cwd": "proj" }
|
||||
},
|
||||
"ci--DemoApplicationTest3": {
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin"
|
||||
],
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar"
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java in CI",
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest3",
|
||||
"options": { "cwd": "proj" }
|
||||
},
|
||||
"ci--DemoApplicationTest2": {
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin"
|
||||
],
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar"
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java in CI",
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest2",
|
||||
"options": { "cwd": "proj" }
|
||||
},
|
||||
"ci--DemoApplicationTest9": {
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin"
|
||||
],
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar"
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java in CI",
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest9",
|
||||
"options": { "cwd": "proj" }
|
||||
},
|
||||
"ci--DemoApplicationTest": {
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest.java"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin"
|
||||
],
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar"
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest.java in CI",
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest",
|
||||
"options": { "cwd": "proj" }
|
||||
},
|
||||
"ci--DemoApplicationTest5": {
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin"
|
||||
],
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar"
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java in CI",
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest5",
|
||||
"options": { "cwd": "proj" }
|
||||
},
|
||||
"ci--DemoApplicationTest4": {
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin"
|
||||
],
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar"
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java in CI",
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest4",
|
||||
"options": { "cwd": "proj" }
|
||||
},
|
||||
"ci--DemoApplicationTest8": {
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin"
|
||||
],
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
"application:classes",
|
||||
"application:compileJava",
|
||||
"library:jar"
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java in CI",
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"command": "./gradlew :application:test --tests DemoApplicationTest8",
|
||||
"options": { "cwd": "proj" }
|
||||
},
|
||||
"ci": {
|
||||
"inputs": [
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java",
|
||||
"{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/build/classes/java/test",
|
||||
"{projectRoot}/build/generated/sources/annotationProcessor/java/test",
|
||||
"{projectRoot}/build/generated/sources/headers/java/test",
|
||||
"{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin"
|
||||
],
|
||||
"cache": true,
|
||||
"dependsOn": [
|
||||
{
|
||||
"target": "ci--DemoApplicationTest10",
|
||||
"projects": "self",
|
||||
"params": "forward"
|
||||
},
|
||||
{
|
||||
"target": "ci--DemoApplicationTest7",
|
||||
"projects": "self",
|
||||
"params": "forward"
|
||||
},
|
||||
{
|
||||
"target": "ci--DemoApplicationTest6",
|
||||
"projects": "self",
|
||||
"params": "forward"
|
||||
},
|
||||
{
|
||||
"target": "ci--DemoApplicationTest3",
|
||||
"projects": "self",
|
||||
"params": "forward"
|
||||
},
|
||||
{
|
||||
"target": "ci--DemoApplicationTest2",
|
||||
"projects": "self",
|
||||
"params": "forward"
|
||||
},
|
||||
{
|
||||
"target": "ci--DemoApplicationTest9",
|
||||
"projects": "self",
|
||||
"params": "forward"
|
||||
},
|
||||
{
|
||||
"target": "ci--DemoApplicationTest",
|
||||
"projects": "self",
|
||||
"params": "forward"
|
||||
},
|
||||
{
|
||||
"target": "ci--DemoApplicationTest5",
|
||||
"projects": "self",
|
||||
"params": "forward"
|
||||
},
|
||||
{
|
||||
"target": "ci--DemoApplicationTest4",
|
||||
"projects": "self",
|
||||
"params": "forward"
|
||||
},
|
||||
{
|
||||
"target": "ci--DemoApplicationTest8",
|
||||
"projects": "self",
|
||||
"params": "forward"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs Gradle Tests in CI",
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"options": { "cwd": "proj" },
|
||||
"executor": "nx:noop"
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"targetGroups": {
|
||||
"verification": ["ci"]
|
||||
},
|
||||
"technologies": ["gradle"]
|
||||
},
|
||||
"name": "application"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,203 @@
|
||||
import { existsSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
||||
import {
|
||||
AggregateCreateNodesError,
|
||||
hashArray,
|
||||
ProjectConfiguration,
|
||||
ProjectGraphExternalNode,
|
||||
readJsonFile,
|
||||
StaticDependency,
|
||||
writeJsonFile,
|
||||
} from '@nx/devkit';
|
||||
|
||||
import { hashWithWorkspaceContext } from 'nx/src/utils/workspace-context';
|
||||
import { gradleConfigAndTestGlob } from '../../utils/split-config-files';
|
||||
import { workspaceDataDirectory } from 'nx/src/utils/cache-directory';
|
||||
import { getNxProjectGraphLines } from './get-project-graph-lines';
|
||||
import { GradlePluginOptions } from './gradle-plugin-options';
|
||||
import { hashObject } from 'nx/src/devkit-internals';
|
||||
|
||||
// the output json file from the gradle plugin
|
||||
export interface ProjectGraphReport {
|
||||
nodes: {
|
||||
[appRoot: string]: Partial<ProjectConfiguration>;
|
||||
};
|
||||
dependencies: Array<StaticDependency>;
|
||||
externalNodes?: Record<string, ProjectGraphExternalNode>;
|
||||
}
|
||||
|
||||
export interface ProjectGraphReportCache extends ProjectGraphReport {
|
||||
hash: string;
|
||||
}
|
||||
|
||||
function readProjectGraphReportCache(
|
||||
cachePath: string,
|
||||
hash: string
|
||||
): ProjectGraphReport | undefined {
|
||||
const projectGraphReportCache: Partial<ProjectGraphReportCache> = existsSync(
|
||||
cachePath
|
||||
)
|
||||
? readJsonFile(cachePath)
|
||||
: undefined;
|
||||
if (!projectGraphReportCache || projectGraphReportCache.hash !== hash) {
|
||||
return;
|
||||
}
|
||||
return projectGraphReportCache as ProjectGraphReport;
|
||||
}
|
||||
|
||||
export function writeProjectGraphReportToCache(
|
||||
cachePath: string,
|
||||
results: ProjectGraphReport
|
||||
) {
|
||||
let projectGraphReportJson: ProjectGraphReportCache = {
|
||||
hash: gradleCurrentConfigHash,
|
||||
...results,
|
||||
};
|
||||
|
||||
writeJsonFile(cachePath, projectGraphReportJson);
|
||||
}
|
||||
|
||||
let projectGraphReportCache: ProjectGraphReport;
|
||||
let gradleCurrentConfigHash: string;
|
||||
let projectGraphReportCachePath: string = join(
|
||||
workspaceDataDirectory,
|
||||
'gradle-nodes.hash'
|
||||
);
|
||||
|
||||
export function getCurrentProjectGraphReport(): ProjectGraphReport {
|
||||
if (!projectGraphReportCache) {
|
||||
throw new AggregateCreateNodesError(
|
||||
[
|
||||
[
|
||||
null,
|
||||
new Error(
|
||||
`Expected cached gradle report. Please open an issue at https://github.com/nrwl/nx/issues/new/choose`
|
||||
),
|
||||
],
|
||||
],
|
||||
[]
|
||||
);
|
||||
}
|
||||
return projectGraphReportCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function populates the gradle report cache.
|
||||
* For each gradlew file, it runs the `nxProjectGraph` task and processes the output.
|
||||
* It will throw an error if both tasks fail.
|
||||
* It will accumulate the output of all gradlew files.
|
||||
* @param workspaceRoot
|
||||
* @param gradlewFiles absolute paths to all gradlew files in the workspace
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
export async function populateProjectGraph(
|
||||
workspaceRoot: string,
|
||||
gradlewFiles: string[],
|
||||
options: GradlePluginOptions
|
||||
): Promise<void> {
|
||||
const gradleConfigHash = hashArray([
|
||||
await hashWithWorkspaceContext(workspaceRoot, [gradleConfigAndTestGlob]),
|
||||
hashObject(options),
|
||||
process.env.CI,
|
||||
]);
|
||||
projectGraphReportCache ??= readProjectGraphReportCache(
|
||||
projectGraphReportCachePath,
|
||||
gradleConfigHash
|
||||
);
|
||||
if (
|
||||
projectGraphReportCache &&
|
||||
(!gradleCurrentConfigHash || gradleConfigHash === gradleCurrentConfigHash)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const gradleProjectGraphReportStart = performance.mark(
|
||||
'gradleProjectGraphReport:start'
|
||||
);
|
||||
|
||||
const projectGraphLines = await gradlewFiles.reduce(
|
||||
async (
|
||||
projectGraphLines: Promise<string[]>,
|
||||
gradlewFile: string
|
||||
): Promise<string[]> => {
|
||||
const getNxProjectGraphLinesStart = performance.mark(
|
||||
`${gradlewFile}GetNxProjectGraphLines:start`
|
||||
);
|
||||
const allLines = await projectGraphLines;
|
||||
const currentLines = await getNxProjectGraphLines(
|
||||
gradlewFile,
|
||||
gradleConfigHash,
|
||||
options
|
||||
);
|
||||
const getNxProjectGraphLinesEnd = performance.mark(
|
||||
`${gradlewFile}GetNxProjectGraphLines:end`
|
||||
);
|
||||
performance.measure(
|
||||
`${gradlewFile}GetNxProjectGraphLines`,
|
||||
getNxProjectGraphLinesStart.name,
|
||||
getNxProjectGraphLinesEnd.name
|
||||
);
|
||||
return [...allLines, ...currentLines];
|
||||
},
|
||||
Promise.resolve([])
|
||||
);
|
||||
|
||||
const gradleProjectGraphReportEnd = performance.mark(
|
||||
'gradleProjectGraphReport:end'
|
||||
);
|
||||
performance.measure(
|
||||
'gradleProjectGraphReport',
|
||||
gradleProjectGraphReportStart.name,
|
||||
gradleProjectGraphReportEnd.name
|
||||
);
|
||||
gradleCurrentConfigHash = gradleConfigHash;
|
||||
projectGraphReportCache = processNxProjectGraph(projectGraphLines);
|
||||
writeProjectGraphReportToCache(
|
||||
projectGraphReportCachePath,
|
||||
projectGraphReportCache
|
||||
);
|
||||
}
|
||||
|
||||
export function processNxProjectGraph(
|
||||
projectGraphLines: string[]
|
||||
): ProjectGraphReport {
|
||||
let index = 0;
|
||||
let projectGraphReportForAllProjects: ProjectGraphReport = {
|
||||
nodes: {},
|
||||
dependencies: [],
|
||||
externalNodes: {},
|
||||
};
|
||||
while (index < projectGraphLines.length) {
|
||||
const line = projectGraphLines[index].trim();
|
||||
if (line.startsWith('> Task ') && line.endsWith(':nxProjectGraph')) {
|
||||
while (
|
||||
index < projectGraphLines.length &&
|
||||
!projectGraphLines[index].includes('.json')
|
||||
) {
|
||||
index++;
|
||||
}
|
||||
const file = projectGraphLines[index];
|
||||
const projectGraphReportJson: ProjectGraphReport =
|
||||
readJsonFile<ProjectGraphReport>(file);
|
||||
projectGraphReportForAllProjects.nodes = {
|
||||
...projectGraphReportForAllProjects.nodes,
|
||||
...projectGraphReportJson.nodes,
|
||||
};
|
||||
if (projectGraphReportJson.dependencies) {
|
||||
projectGraphReportForAllProjects.dependencies.push(
|
||||
...projectGraphReportJson.dependencies
|
||||
);
|
||||
}
|
||||
if (Object.keys(projectGraphReportJson.externalNodes ?? {}).length > 0) {
|
||||
projectGraphReportForAllProjects.externalNodes = {
|
||||
...projectGraphReportForAllProjects.externalNodes,
|
||||
...projectGraphReportJson.externalNodes,
|
||||
};
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
return projectGraphReportForAllProjects;
|
||||
}
|
||||
90
packages/gradle/src/plugin/utils/get-project-graph-lines.ts
Normal file
90
packages/gradle/src/plugin/utils/get-project-graph-lines.ts
Normal file
@ -0,0 +1,90 @@
|
||||
import { AggregateCreateNodesError, output, workspaceRoot } from '@nx/devkit';
|
||||
import { execGradleAsync, newLineSeparator } from '../../utils/exec-gradle';
|
||||
import { GradlePluginOptions } from './gradle-plugin-options';
|
||||
import { dirname } from 'node:path';
|
||||
|
||||
export async function getNxProjectGraphLines(
|
||||
gradlewFile: string,
|
||||
gradleConfigHash: string,
|
||||
gradlePluginOptions: GradlePluginOptions
|
||||
): Promise<string[]> {
|
||||
if (process.env.VERCEL) {
|
||||
// skip on Vercel
|
||||
return [];
|
||||
}
|
||||
|
||||
let nxProjectGraphBuffer: Buffer;
|
||||
|
||||
const gradlePluginOptionsArgs =
|
||||
Object.entries(gradlePluginOptions ?? {})?.map(
|
||||
([key, value]) => `-P${key}=${value}`
|
||||
) ?? [];
|
||||
|
||||
try {
|
||||
nxProjectGraphBuffer = await execGradleAsync(gradlewFile, [
|
||||
'nxProjectGraph',
|
||||
`-Phash=${gradleConfigHash}`,
|
||||
'--no-configuration-cache', // disable configuration cache
|
||||
'--parallel', // add parallel to improve performance
|
||||
'--build-cache', // enable build cache
|
||||
'--warning-mode',
|
||||
'none',
|
||||
...gradlePluginOptionsArgs,
|
||||
`-Pcwd=${dirname(gradlewFile)}`,
|
||||
`-PworkspaceRoot=${workspaceRoot}`,
|
||||
process.env.NX_VERBOSE_LOGGING ? '--info' : '',
|
||||
]);
|
||||
} catch (e: Buffer | Error | any) {
|
||||
if (e.toString()?.includes('ERROR: JAVA_HOME')) {
|
||||
throw new AggregateCreateNodesError(
|
||||
[
|
||||
[
|
||||
gradlewFile,
|
||||
new Error(
|
||||
`Could not find Java. Please install Java and try again: https://www.java.com/en/download/help/index_installing.html.\n\r${e.toString()}`
|
||||
),
|
||||
],
|
||||
],
|
||||
[]
|
||||
);
|
||||
} else if (e.toString()?.includes(`Task 'nxProjectGraph' not found`)) {
|
||||
throw new AggregateCreateNodesError(
|
||||
[
|
||||
[
|
||||
gradlewFile,
|
||||
new Error(
|
||||
`Could not run 'nxProjectGraph' task. Please run 'nx generate @nx/gradle:init' to generate the necessary tasks.\n\r${e.toString()}`
|
||||
),
|
||||
],
|
||||
],
|
||||
[]
|
||||
);
|
||||
} else {
|
||||
throw new AggregateCreateNodesError(
|
||||
[
|
||||
[
|
||||
gradlewFile,
|
||||
new Error(
|
||||
`Could not run 'nxProjectGraph' Gradle task. Please install Gradle and try again: https://gradle.org/install/.\r\n${e.toString()}`
|
||||
),
|
||||
],
|
||||
],
|
||||
[]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const projectGraphLines = nxProjectGraphBuffer
|
||||
.toString()
|
||||
.split(newLineSeparator)
|
||||
.filter((line) => line.trim() !== '');
|
||||
|
||||
if (process.env.NX_VERBOSE_LOGGING === 'true') {
|
||||
output.log({
|
||||
title: `Successfully ran 'nxProjectGraph' task using ${gradlewFile} with hash ${gradleConfigHash}`,
|
||||
bodyLines: projectGraphLines,
|
||||
});
|
||||
}
|
||||
|
||||
return projectGraphLines;
|
||||
}
|
||||
13
packages/gradle/src/plugin/utils/gradle-plugin-options.ts
Normal file
13
packages/gradle/src/plugin/utils/gradle-plugin-options.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export interface GradlePluginOptions {
|
||||
testTargetName?: string;
|
||||
ciTargetName?: string;
|
||||
[taskTargetName: string]: string | undefined | boolean;
|
||||
}
|
||||
|
||||
export function normalizeOptions(
|
||||
options: GradlePluginOptions
|
||||
): GradlePluginOptions {
|
||||
options ??= {};
|
||||
options.testTargetName ??= 'test';
|
||||
return options;
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';
|
||||
import { findGraldewFile } from './exec-gradle';
|
||||
import { findGradlewFile } from './exec-gradle';
|
||||
|
||||
describe('exec gradle', () => {
|
||||
describe('findGraldewFile', () => {
|
||||
describe('findGradlewFile', () => {
|
||||
let tempFs: TempFs;
|
||||
let cwd: string;
|
||||
|
||||
@ -27,14 +27,14 @@ describe('exec gradle', () => {
|
||||
'nested/nested/proj/src/test/java/test/aTest.java': ``,
|
||||
'nested/nested/proj/src/test/java/test/bTest.java': ``,
|
||||
});
|
||||
let gradlewFile = findGraldewFile('proj/build.gradle', tempFs.tempDir);
|
||||
let gradlewFile = findGradlewFile('proj/build.gradle', tempFs.tempDir);
|
||||
expect(gradlewFile).toEqual('gradlew');
|
||||
gradlewFile = findGraldewFile(
|
||||
gradlewFile = findGradlewFile(
|
||||
'nested/nested/proj/build.gradle',
|
||||
tempFs.tempDir
|
||||
);
|
||||
expect(gradlewFile).toEqual('gradlew');
|
||||
gradlewFile = findGraldewFile(
|
||||
gradlewFile = findGradlewFile(
|
||||
'nested/nested/proj/settings.gradle',
|
||||
tempFs.tempDir
|
||||
);
|
||||
@ -54,16 +54,16 @@ describe('exec gradle', () => {
|
||||
'nested/nested/proj/src/test/java/test/bTest.java': ``,
|
||||
});
|
||||
|
||||
let gradlewFile = findGraldewFile('proj/build.gradle', tempFs.tempDir);
|
||||
let gradlewFile = findGradlewFile('proj/build.gradle', tempFs.tempDir);
|
||||
expect(gradlewFile).toEqual('proj/gradlew');
|
||||
gradlewFile = findGraldewFile('proj/settings.gradle', tempFs.tempDir);
|
||||
gradlewFile = findGradlewFile('proj/settings.gradle', tempFs.tempDir);
|
||||
expect(gradlewFile).toEqual('proj/gradlew');
|
||||
gradlewFile = findGraldewFile(
|
||||
gradlewFile = findGradlewFile(
|
||||
'nested/nested/proj/build.gradle',
|
||||
tempFs.tempDir
|
||||
);
|
||||
expect(gradlewFile).toEqual('nested/nested/proj/gradlew');
|
||||
gradlewFile = findGraldewFile(
|
||||
gradlewFile = findGradlewFile(
|
||||
'nested/nested/proj/settings.gradle',
|
||||
tempFs.tempDir
|
||||
);
|
||||
@ -80,7 +80,7 @@ describe('exec gradle', () => {
|
||||
'nested/nested/proj/src/test/java/test/bTest.java': ``,
|
||||
});
|
||||
expect(() =>
|
||||
findGraldewFile('proj/build.gradle', tempFs.tempDir)
|
||||
findGradlewFile('proj/build.gradle', tempFs.tempDir)
|
||||
).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
@ -4,6 +4,14 @@ import { existsSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { LARGE_BUFFER } from 'nx/src/executors/run-commands/run-commands.impl';
|
||||
|
||||
export const fileSeparator = process.platform.startsWith('win')
|
||||
? 'file:///'
|
||||
: 'file://';
|
||||
|
||||
export const newLineSeparator = process.platform.startsWith('win')
|
||||
? '\r\n'
|
||||
: '\n';
|
||||
|
||||
/**
|
||||
* For gradle command, it needs to be run from the directory of the gradle binary
|
||||
* @returns gradle binary file name
|
||||
@ -54,13 +62,13 @@ export function execGradleAsync(
|
||||
|
||||
/**
|
||||
* This function recursively finds the nearest gradlew file in the workspace
|
||||
* @param originalFileToSearch the original file to search for
|
||||
* @param originalFileToSearch the original file to search for, relative to workspace root, file path not directory path
|
||||
* @param wr workspace root
|
||||
* @param currentSearchPath the path to start searching for gradlew file
|
||||
* @returns the relative path of the gradlew file to workspace root, throws an error if gradlew file is not found
|
||||
* It will return gradlew.bat file on windows and gradlew file on other platforms
|
||||
* It will return relative path to workspace root of gradlew.bat file on windows and gradlew file on other platforms
|
||||
*/
|
||||
export function findGraldewFile(
|
||||
export function findGradlewFile(
|
||||
originalFileToSearch: string,
|
||||
wr: string = workspaceRoot,
|
||||
currentSearchPath?: string
|
||||
@ -92,5 +100,5 @@ export function findGraldewFile(
|
||||
}
|
||||
}
|
||||
|
||||
return findGraldewFile(originalFileToSearch, wr, parent);
|
||||
return findGradlewFile(originalFileToSearch, wr, parent);
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@ export const GRADLE_TEST_FILES = [
|
||||
'**/src/test/kotlin/**/*Test.kt',
|
||||
'**/src/test/java/**/*Tests.java',
|
||||
'**/src/test/kotlin/**/*Tests.kt',
|
||||
'**/src/test/groovy/**/*Test.groovy',
|
||||
'**/src/test/groovy/**/*Tests.groovy',
|
||||
];
|
||||
|
||||
export const gradleConfigGlob = combineGlobPatterns(
|
||||
|
||||
@ -1 +1,4 @@
|
||||
export const nxVersion = require('../../package.json').version;
|
||||
|
||||
export const gradleProjectGraphPluginName = 'dev.nx.gradle.project-graph';
|
||||
export const gradleProjectGraphVersion = '0.0.2';
|
||||
|
||||
876
pnpm-lock.yaml
generated
876
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
18
settings.gradle.kts
Normal file
18
settings.gradle.kts
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* The settings file is used to specify which projects to include in your build.
|
||||
* For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.5/userguide/building_swift_projects.html in the Gradle documentation.
|
||||
*/
|
||||
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "nx"
|
||||
includeBuild("./packages/gradle/project-graph")
|
||||
Loading…
x
Reference in New Issue
Block a user