@nx/gradle 19.0.0-beta.1 → 19.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/generators.json +5 -0
- package/package.json +2 -2
- package/src/generators/ci-workflow/files/circleci/.circleci/config.yml.template +32 -0
- package/src/generators/ci-workflow/files/github/.github/workflows/__workflowFileName__.yml.template +40 -0
- package/src/generators/ci-workflow/generator.d.ts +9 -0
- package/src/generators/ci-workflow/generator.js +48 -0
- package/src/generators/ci-workflow/schema.json +40 -0
- package/src/plugin/nodes.d.ts +3 -3
- package/src/plugin/nodes.js +9 -17
- package/src/utils/exec-gradle.d.ts +3 -2
- package/src/utils/exec-gradle.js +5 -4
- package/src/utils/get-gradle-report.d.ts +3 -2
- package/src/utils/get-gradle-report.js +30 -15
package/generators.json
CHANGED
@@ -6,6 +6,11 @@
|
|
6
6
|
"factory": "./src/generators/init/init#initGenerator",
|
7
7
|
"schema": "./src/generators/init/schema.json",
|
8
8
|
"description": "Initializes a Gradle project in the current workspace"
|
9
|
+
},
|
10
|
+
"ci-workflow": {
|
11
|
+
"factory": "./src/generators/ci-workflow/generator",
|
12
|
+
"schema": "./src/generators/ci-workflow/schema.json",
|
13
|
+
"description": "Setup a CI Workflow to run Nx in CI"
|
9
14
|
}
|
10
15
|
}
|
11
16
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@nx/gradle",
|
3
|
-
"version": "19.0.0-beta.
|
3
|
+
"version": "19.0.0-beta.10",
|
4
4
|
"private": false,
|
5
5
|
"description": "The Nx Plugin for Gradle allows Gradle tasks to be run through Nx",
|
6
6
|
"repository": {
|
@@ -33,7 +33,7 @@
|
|
33
33
|
"migrations": "./migrations.json"
|
34
34
|
},
|
35
35
|
"dependencies": {
|
36
|
-
"@nx/devkit": "19.0.0-beta.
|
36
|
+
"@nx/devkit": "19.0.0-beta.10"
|
37
37
|
},
|
38
38
|
"publishConfig": {
|
39
39
|
"access": "public"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
version: 2.1
|
2
|
+
|
3
|
+
orbs:
|
4
|
+
nx: nrwl/nx@1.6.2
|
5
|
+
|
6
|
+
jobs:
|
7
|
+
main:
|
8
|
+
environment:
|
9
|
+
# Configure the JVM and Gradle to avoid OOM errors
|
10
|
+
_JAVA_OPTIONS: "-Xmx3g"
|
11
|
+
GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2"
|
12
|
+
docker:
|
13
|
+
- image: cimg/openjdk:17.0-node
|
14
|
+
steps:
|
15
|
+
- checkout
|
16
|
+
|
17
|
+
# Connect your workspace on <%= nxCloudHost %> and uncomment this to enable task distribution.
|
18
|
+
# The "--stop-agents-after" is optional, but allows idle agents to shut down once the "build" targets have been requested
|
19
|
+
# - run: <%= packageManagerPrefix %> nx-cloud start-ci-run --distribute-on="5 linux-medium-jvm" --stop-agents-after="build"
|
20
|
+
|
21
|
+
- nx/set-shas:
|
22
|
+
main-branch-name: '<%= mainBranch %>'
|
23
|
+
|
24
|
+
<% for (const command of commands) { %>
|
25
|
+
- run: <%= command %><% } %>
|
26
|
+
|
27
|
+
workflows:
|
28
|
+
version: 2
|
29
|
+
|
30
|
+
<%= workflowFileName %>:
|
31
|
+
jobs:
|
32
|
+
- main
|
package/src/generators/ci-workflow/files/github/.github/workflows/__workflowFileName__.yml.template
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
name: <%= workflowName %>
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- <%= mainBranch %>
|
7
|
+
pull_request:
|
8
|
+
|
9
|
+
permissions:
|
10
|
+
actions: read
|
11
|
+
contents: read
|
12
|
+
|
13
|
+
jobs:
|
14
|
+
main:
|
15
|
+
runs-on: ubuntu-latest
|
16
|
+
steps:
|
17
|
+
- uses: actions/checkout@v4
|
18
|
+
with:
|
19
|
+
fetch-depth: 0
|
20
|
+
|
21
|
+
# Connect your workspace on <%= nxCloudHost %> and uncomment this to enable task distribution.
|
22
|
+
# The "--stop-agents-after" is optional, but allows idle agents to shut down once the "build" targets have been requested
|
23
|
+
# - run: <%= packageManagerPrefix %> nx-cloud start-ci-run --distribute-on="5 linux-medium-jvm" --stop-agents-after="build"
|
24
|
+
|
25
|
+
- name: Set up JDK 17 for x64
|
26
|
+
uses: actions/setup-java@v4
|
27
|
+
with:
|
28
|
+
java-version: '17'
|
29
|
+
distribution: 'temurin'
|
30
|
+
architecture: x64
|
31
|
+
|
32
|
+
- name: Setup Gradle
|
33
|
+
uses: gradle/gradle-build-action@v2
|
34
|
+
|
35
|
+
- uses: nrwl/nx-set-shas@v4
|
36
|
+
|
37
|
+
- run: git branch --track main origin/main
|
38
|
+
if: ${{ github.event_name == 'pull_request' }}
|
39
|
+
<% for (const command of commands) { %>
|
40
|
+
- run: <%= command %><% } %>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { Tree } from '@nx/devkit';
|
2
|
+
export interface Schema {
|
3
|
+
name: string;
|
4
|
+
ci: 'github' | 'circleci';
|
5
|
+
packageManager?: null;
|
6
|
+
commands?: string[];
|
7
|
+
}
|
8
|
+
export declare function ciWorkflowGenerator(tree: Tree, schema: Schema): Promise<void>;
|
9
|
+
export default ciWorkflowGenerator;
|
@@ -0,0 +1,48 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.ciWorkflowGenerator = void 0;
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
5
|
+
const path_1 = require("path");
|
6
|
+
const nx_cloud_utils_1 = require("nx/src/utils/nx-cloud-utils");
|
7
|
+
const default_base_1 = require("nx/src/utils/default-base");
|
8
|
+
function getCiCommands(ci, mainBranch) {
|
9
|
+
switch (ci) {
|
10
|
+
case 'circleci': {
|
11
|
+
return [`./nx affected --base=$NX_BASE --head=$NX_HEAD -t test build`];
|
12
|
+
}
|
13
|
+
default: {
|
14
|
+
return [`./nx affected -t test build`];
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}
|
18
|
+
async function ciWorkflowGenerator(tree, schema) {
|
19
|
+
const ci = schema.ci;
|
20
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
21
|
+
const nxCloudUsed = (0, nx_cloud_utils_1.isNxCloudUsed)(nxJson);
|
22
|
+
if (!nxCloudUsed) {
|
23
|
+
throw new Error('This workspace is not connected to Nx Cloud.');
|
24
|
+
}
|
25
|
+
const options = getTemplateData(schema, nxJson);
|
26
|
+
(0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, 'files', ci), '', options);
|
27
|
+
await (0, devkit_1.formatFiles)(tree);
|
28
|
+
}
|
29
|
+
exports.ciWorkflowGenerator = ciWorkflowGenerator;
|
30
|
+
function getTemplateData(options, nxJson) {
|
31
|
+
const { name: workflowName, fileName: workflowFileName } = (0, devkit_1.names)(options.name);
|
32
|
+
const packageManager = (0, devkit_1.detectPackageManager)();
|
33
|
+
const { exec: packageManagerPrefix } = (0, devkit_1.getPackageManagerCommand)(packageManager);
|
34
|
+
const nxCloudUrl = (0, nx_cloud_utils_1.getNxCloudUrl)(nxJson);
|
35
|
+
const nxCloudHost = new URL(nxCloudUrl).host;
|
36
|
+
const mainBranch = (0, default_base_1.deduceDefaultBase)();
|
37
|
+
const commands = options.commands ?? getCiCommands(options.ci, mainBranch);
|
38
|
+
return {
|
39
|
+
workflowName,
|
40
|
+
workflowFileName,
|
41
|
+
packageManager,
|
42
|
+
packageManagerPrefix,
|
43
|
+
commands,
|
44
|
+
mainBranch,
|
45
|
+
nxCloudHost,
|
46
|
+
};
|
47
|
+
}
|
48
|
+
exports.default = ciWorkflowGenerator;
|
@@ -0,0 +1,40 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "https://json-schema.org/schema",
|
3
|
+
"$id": "NxGradleCiWorkflowSchema",
|
4
|
+
"title": "Gradle CI Workflow Generator",
|
5
|
+
"description": "Setup a CI Workflow to run Nx in CI.",
|
6
|
+
"type": "object",
|
7
|
+
"properties": {
|
8
|
+
"ci": {
|
9
|
+
"type": "string",
|
10
|
+
"description": "CI provider.",
|
11
|
+
"enum": ["github", "circleci"],
|
12
|
+
"x-prompt": {
|
13
|
+
"message": "What is your target CI provider?",
|
14
|
+
"type": "list",
|
15
|
+
"items": [
|
16
|
+
{
|
17
|
+
"value": "github",
|
18
|
+
"label": "GitHub Actions"
|
19
|
+
},
|
20
|
+
{
|
21
|
+
"value": "circleci",
|
22
|
+
"label": "Circle CI"
|
23
|
+
}
|
24
|
+
]
|
25
|
+
}
|
26
|
+
},
|
27
|
+
"name": {
|
28
|
+
"type": "string",
|
29
|
+
"description": "Workflow name.",
|
30
|
+
"$default": {
|
31
|
+
"$source": "argv",
|
32
|
+
"index": 0
|
33
|
+
},
|
34
|
+
"default": "CI",
|
35
|
+
"x-prompt": "How should we name your workflow?",
|
36
|
+
"pattern": "^[a-zA-Z].*$"
|
37
|
+
}
|
38
|
+
},
|
39
|
+
"required": ["ci", "name"]
|
40
|
+
}
|
package/src/plugin/nodes.d.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { CreateNodes, TargetConfiguration } from '@nx/devkit';
|
1
|
+
import { CreateNodes, ProjectConfiguration, TargetConfiguration } from '@nx/devkit';
|
2
2
|
export interface GradlePluginOptions {
|
3
3
|
testTargetName?: string;
|
4
4
|
classesTargetName?: string;
|
@@ -8,11 +8,11 @@ export interface GradlePluginOptions {
|
|
8
8
|
export declare const calculatedTargets: Record<string, {
|
9
9
|
name: string;
|
10
10
|
targets: Record<string, TargetConfiguration>;
|
11
|
-
|
11
|
+
metadata: ProjectConfiguration['metadata'];
|
12
12
|
}>;
|
13
13
|
export declare function writeTargetsToCache(targets: Record<string, {
|
14
14
|
name: string;
|
15
15
|
targets: Record<string, TargetConfiguration>;
|
16
|
-
|
16
|
+
metadata: ProjectConfiguration['metadata'];
|
17
17
|
}>): void;
|
18
18
|
export declare const createNodes: CreateNodes<GradlePluginOptions>;
|
package/src/plugin/nodes.js
CHANGED
@@ -33,12 +33,7 @@ exports.createNodes = [
|
|
33
33
|
exports.calculatedTargets[hash] = targetsCache[hash];
|
34
34
|
return {
|
35
35
|
projects: {
|
36
|
-
[projectRoot]:
|
37
|
-
...targetsCache[hash],
|
38
|
-
metadata: {
|
39
|
-
technologies: ['gradle'],
|
40
|
-
},
|
41
|
-
},
|
36
|
+
[projectRoot]: targetsCache[hash],
|
42
37
|
},
|
43
38
|
};
|
44
39
|
}
|
@@ -58,19 +53,16 @@ exports.createNodes = [
|
|
58
53
|
});
|
59
54
|
}
|
60
55
|
const outputDirs = gradleFileToOutputDirsMap.get(gradleFilePath);
|
61
|
-
const { targets, targetGroups } = createGradleTargets(tasks,
|
62
|
-
exports.calculatedTargets[hash] = {
|
63
|
-
name: projectName,
|
64
|
-
targets,
|
65
|
-
targetGroups,
|
66
|
-
};
|
56
|
+
const { targets, targetGroups } = createGradleTargets(tasks, options, context, outputDirs, gradleProject);
|
67
57
|
const project = {
|
68
58
|
name: projectName,
|
69
59
|
targets,
|
70
60
|
metadata: {
|
61
|
+
targetGroups,
|
71
62
|
technologies: ['gradle'],
|
72
63
|
},
|
73
64
|
};
|
65
|
+
exports.calculatedTargets[hash] = project;
|
74
66
|
return {
|
75
67
|
projects: {
|
76
68
|
[projectRoot]: project,
|
@@ -83,7 +75,7 @@ exports.createNodes = [
|
|
83
75
|
}
|
84
76
|
},
|
85
77
|
];
|
86
|
-
function createGradleTargets(tasks,
|
78
|
+
function createGradleTargets(tasks, options, context, outputDirs, gradleProject) {
|
87
79
|
const inputsMap = createInputsMap(context);
|
88
80
|
const targets = {};
|
89
81
|
const targetGroups = {};
|
@@ -91,14 +83,14 @@ function createGradleTargets(tasks, projectRoot, options, context, outputDirs) {
|
|
91
83
|
const targetName = options?.[`${task.name}TargetName`] ?? task.name;
|
92
84
|
const outputs = outputDirs.get(task.name);
|
93
85
|
targets[targetName] = {
|
94
|
-
command: `${(0, exec_gradle_1.
|
95
|
-
options: {
|
96
|
-
cwd: projectRoot,
|
97
|
-
},
|
86
|
+
command: `${(0, exec_gradle_1.getGradleExecFile)()} ${gradleProject ? gradleProject + ':' : ''}${task.name}`,
|
98
87
|
cache: cacheableTaskType.has(task.type),
|
99
88
|
inputs: inputsMap[task.name],
|
100
89
|
outputs: outputs ? [outputs] : undefined,
|
101
90
|
dependsOn: dependsOnMap[task.name],
|
91
|
+
metadata: {
|
92
|
+
technologies: ['gradle'],
|
93
|
+
},
|
102
94
|
};
|
103
95
|
if (!targetGroups[task.type]) {
|
104
96
|
targetGroups[task.type] = [];
|
@@ -2,6 +2,7 @@
|
|
2
2
|
/// <reference types="node" />
|
3
3
|
import { ExecFileOptions } from 'child_process';
|
4
4
|
import { ExecFileSyncOptionsWithBufferEncoding } from 'node:child_process';
|
5
|
-
export declare function execGradle(args: string[], execOptions
|
5
|
+
export declare function execGradle(args: string[], execOptions?: ExecFileSyncOptionsWithBufferEncoding): Buffer;
|
6
6
|
export declare function getGradleBinaryPath(): string;
|
7
|
-
export declare function
|
7
|
+
export declare function getGradleExecFile(): string;
|
8
|
+
export declare function execGradleAsync(args: ReadonlyArray<string>, execOptions?: ExecFileOptions): Promise<Buffer>;
|
package/src/utils/exec-gradle.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.execGradleAsync = exports.getGradleBinaryPath = exports.execGradle = void 0;
|
3
|
+
exports.execGradleAsync = exports.getGradleExecFile = exports.getGradleBinaryPath = exports.execGradle = void 0;
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
5
5
|
const node_child_process_1 = require("node:child_process");
|
6
6
|
const node_fs_1 = require("node:fs");
|
@@ -21,11 +21,12 @@ function getGradleBinaryPath() {
|
|
21
21
|
return gradleBinaryPath;
|
22
22
|
}
|
23
23
|
exports.getGradleBinaryPath = getGradleBinaryPath;
|
24
|
+
function getGradleExecFile() {
|
25
|
+
return process.platform.startsWith('win') ? '.\\gradlew.bat' : './gradlew';
|
26
|
+
}
|
27
|
+
exports.getGradleExecFile = getGradleExecFile;
|
24
28
|
function execGradleAsync(args, execOptions) {
|
25
29
|
const gradleBinaryPath = getGradleBinaryPath();
|
26
|
-
if (!(0, node_fs_1.existsSync)(gradleBinaryPath)) {
|
27
|
-
throw new Error('Gradle is not setup. Run "gradle init"');
|
28
|
-
}
|
29
30
|
return new Promise((res, rej) => {
|
30
31
|
const cp = (0, node_child_process_1.execFile)(gradleBinaryPath, args, execOptions);
|
31
32
|
let stdout = Buffer.from('');
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
export declare const fileSeparator: string;
|
2
|
+
export interface GradleReport {
|
2
3
|
gradleFileToGradleProjectMap: Map<string, string>;
|
3
4
|
buildFileToDepsMap: Map<string, string>;
|
4
5
|
gradleFileToOutputDirsMap: Map<string, Map<string, string>>;
|
@@ -7,4 +8,4 @@ interface GradleReport {
|
|
7
8
|
}
|
8
9
|
export declare function invalidateGradleReportCache(): void;
|
9
10
|
export declare function getGradleReport(): GradleReport;
|
10
|
-
export
|
11
|
+
export declare function processProjectReports(projectReportLines: string[]): GradleReport;
|
@@ -1,11 +1,11 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.getGradleReport = exports.invalidateGradleReportCache = void 0;
|
3
|
+
exports.processProjectReports = exports.getGradleReport = exports.invalidateGradleReportCache = exports.fileSeparator = void 0;
|
4
4
|
const node_fs_1 = require("node:fs");
|
5
5
|
const node_path_1 = require("node:path");
|
6
6
|
const devkit_1 = require("@nx/devkit");
|
7
7
|
const exec_gradle_1 = require("./exec-gradle");
|
8
|
-
|
8
|
+
exports.fileSeparator = process.platform.startsWith('win')
|
9
9
|
? 'file:///'
|
10
10
|
: 'file://';
|
11
11
|
const newLineSeparator = process.platform.startsWith('win') ? '\r\n' : '\n';
|
@@ -54,20 +54,29 @@ function processProjectReports(projectReportLines) {
|
|
54
54
|
* e.g. {build.gradle.kts: { projectReportDir: '' testReportDir: '' }}
|
55
55
|
*/
|
56
56
|
const gradleFileToOutputDirsMap = new Map();
|
57
|
-
|
57
|
+
let index = 0;
|
58
|
+
while (index < projectReportLines.length) {
|
59
|
+
const line = projectReportLines[index].trim();
|
58
60
|
if (line.startsWith('> Task ')) {
|
59
|
-
const nextLine = projectReportLines[index + 1];
|
60
61
|
if (line.endsWith(':dependencyReport')) {
|
61
62
|
const gradleProject = line.substring('> Task '.length, line.length - ':dependencyReport'.length);
|
62
|
-
|
63
|
+
while (index < projectReportLines.length &&
|
64
|
+
!projectReportLines[index].includes(exports.fileSeparator)) {
|
65
|
+
index++;
|
66
|
+
}
|
67
|
+
const [_, file] = projectReportLines[index].split(exports.fileSeparator);
|
63
68
|
dependenciesMap.set(gradleProject, file);
|
64
69
|
}
|
65
70
|
if (line.endsWith('propertyReport')) {
|
66
71
|
const gradleProject = line.substring('> Task '.length, line.length - ':propertyReport'.length);
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
72
|
+
while (index < projectReportLines.length &&
|
73
|
+
!projectReportLines[index].includes(exports.fileSeparator)) {
|
74
|
+
index++;
|
75
|
+
}
|
76
|
+
const [_, file] = projectReportLines[index].split(exports.fileSeparator);
|
77
|
+
const propertyReportLines = (0, node_fs_1.existsSync)(file)
|
78
|
+
? (0, node_fs_1.readFileSync)(file).toString().split(newLineSeparator)
|
79
|
+
: [];
|
71
80
|
let projectName, absBuildFilePath, absBuildDirPath;
|
72
81
|
const outputDirMap = new Map();
|
73
82
|
for (const line of propertyReportLines) {
|
@@ -87,7 +96,7 @@ function processProjectReports(projectReportLines) {
|
|
87
96
|
}
|
88
97
|
}
|
89
98
|
if (!projectName || !absBuildFilePath || !absBuildDirPath) {
|
90
|
-
|
99
|
+
continue;
|
91
100
|
}
|
92
101
|
const buildFile = (0, devkit_1.normalizePath)((0, node_path_1.relative)(devkit_1.workspaceRoot, absBuildFilePath));
|
93
102
|
const buildDir = (0, node_path_1.relative)(devkit_1.workspaceRoot, absBuildDirPath);
|
@@ -101,11 +110,15 @@ function processProjectReports(projectReportLines) {
|
|
101
110
|
}
|
102
111
|
if (line.endsWith('taskReport')) {
|
103
112
|
const gradleProject = line.substring('> Task '.length, line.length - ':taskReport'.length);
|
104
|
-
|
113
|
+
while (index < projectReportLines.length &&
|
114
|
+
!projectReportLines[index].includes(exports.fileSeparator)) {
|
115
|
+
index++;
|
116
|
+
}
|
117
|
+
const [_, file] = projectReportLines[index].split(exports.fileSeparator);
|
105
118
|
const taskTypeMap = new Map();
|
106
|
-
const tasksFileLines = (0, node_fs_1.
|
107
|
-
.toString()
|
108
|
-
|
119
|
+
const tasksFileLines = (0, node_fs_1.existsSync)(file)
|
120
|
+
? (0, node_fs_1.readFileSync)(file).toString().split(newLineSeparator)
|
121
|
+
: [];
|
109
122
|
let i = 0;
|
110
123
|
while (i < tasksFileLines.length) {
|
111
124
|
const line = tasksFileLines[i];
|
@@ -125,7 +138,8 @@ function processProjectReports(projectReportLines) {
|
|
125
138
|
gradleProjectToTasksTypeMap.set(gradleProject, taskTypeMap);
|
126
139
|
}
|
127
140
|
}
|
128
|
-
|
141
|
+
index++;
|
142
|
+
}
|
129
143
|
return {
|
130
144
|
gradleFileToGradleProjectMap,
|
131
145
|
buildFileToDepsMap,
|
@@ -134,3 +148,4 @@ function processProjectReports(projectReportLines) {
|
|
134
148
|
gradleProjectToProjectName,
|
135
149
|
};
|
136
150
|
}
|
151
|
+
exports.processProjectReports = processProjectReports;
|