Skip to content

Commit 6b39cf3

Browse files
authored
Gradle V4: New major version of the Gradle task (#20596)
* Removed references to jacoco in code coverage for Gradle V4 * Removed references to Code Coverage in GradleV4 * Removed redundant functions, and references to code coverage in Tests * Updated the minor version of the task * Updated CODEOWNERS and make-options.json * task build after adding task under node20 in make-options.json * update to make-options.json * updated minor version * removed gradlev4 from local packages section in make-options.json, and removed _generated/GradleV4 * Added .npmrc and updated packages * Added .npmrc and updated packages * updated CODEOWNERS file * updated broken link in README * added _generated/README * updated minor version
1 parent 3ca51a0 commit 6b39cf3

File tree

205 files changed

+27631
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

205 files changed

+27631
-0
lines changed

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ Tasks/GradleV2/ @microsoft/azure-pipelines-tasks-and-agent @tarunramsinghani
260260

261261
Tasks/GradleV3/ @microsoft/azure-pipelines-tasks-and-agent @tarunramsinghani
262262

263+
Tasks/GradleV4/ @microsoft/azure-pipelines-tasks-and-agent @tarunramsinghani
264+
263265
Tasks/GruntV0/ @microsoft/azure-pipelines-tasks-and-agent @tarunramsinghani
264266

265267
Tasks/GulpV0/ @microsoft/azure-pipelines-tasks-and-agent @tarunramsinghani

Tasks/GradleV4/.npmrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
registry=https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/
2+
3+
always-auth=true

Tasks/GradleV4/Modules/environment.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import * as tl from 'azure-pipelines-task-lib/task';
2+
import * as javaCommon from 'azure-pipelines-tasks-java-common/java-common';
3+
import { IExecOptions, ToolRunner } from 'azure-pipelines-task-lib/toolrunner';
4+
5+
// Setting the access token env var to both VSTS and AZURE_ARTIFACTS for
6+
// backwards compatibility with repos that already use the older env var.
7+
const accessTokenEnvSettingLegacy: string = 'VSTS_ENV_ACCESS_TOKEN';
8+
const accessTokenEnvSetting: string = 'AZURE_ARTIFACTS_ENV_ACCESS_TOKEN';
9+
10+
/**
11+
* Extract system access token from endpoint
12+
* @returns {string} access token to access account feeds or empty string
13+
*/
14+
function getSystemAccessToken(): string {
15+
tl.debug('Getting credentials for account feeds');
16+
17+
const authorizationData: tl.EndpointAuthorization = tl.getEndpointAuthorization('SYSTEMVSSCONNECTION', false);
18+
19+
if (authorizationData && authorizationData.scheme === 'OAuth') {
20+
tl.debug('Got auth token');
21+
return authorizationData.parameters['AccessToken'];
22+
}
23+
24+
tl.warning(tl.loc('FeedTokenUnavailable'));
25+
26+
return '';
27+
}
28+
29+
/**
30+
* Update JAVA_HOME if user selected specific JDK version or set path manually
31+
* @param {string} javaHomeSelection - value of the `Set JAVA_HOME by` task input
32+
*/
33+
export function setJavaHome(javaHomeSelection: string): void {
34+
let specifiedJavaHome: string;
35+
let javaTelemetryData: any = {};
36+
37+
if (javaHomeSelection === 'JDKVersion') {
38+
tl.debug('Using JDK version to find and set JAVA_HOME');
39+
40+
const jdkVersion: string = tl.getInput('jdkVersion');
41+
const jdkArchitecture: string = tl.getInput('jdkArchitecture');
42+
43+
javaTelemetryData = { 'jdkVersion': jdkVersion };
44+
45+
if (jdkVersion !== 'default') {
46+
specifiedJavaHome = javaCommon.findJavaHome(jdkVersion, jdkArchitecture);
47+
}
48+
} else {
49+
tl.debug('Using path from user input to set JAVA_HOME');
50+
51+
const jdkUserInputPath: string = tl.getPathInput('jdkUserInputPath', true, true);
52+
specifiedJavaHome = jdkUserInputPath;
53+
54+
javaTelemetryData = { 'jdkVersion': 'custom' };
55+
}
56+
57+
javaCommon.publishJavaTelemetry('Gradle', javaTelemetryData);
58+
59+
if (specifiedJavaHome) {
60+
tl.debug(`Set JAVA_HOME to ${specifiedJavaHome}`);
61+
process.env['JAVA_HOME'] = specifiedJavaHome;
62+
}
63+
}
64+
65+
/**
66+
* Get execution options for Gradle.
67+
*
68+
* This function does the following things:
69+
* - Get a snapshot of the process environment variables
70+
* - Update the snapshot to include system access token
71+
* @returns {IExecOptions} object with execution options for Gradle
72+
*/
73+
export function getExecOptions(): IExecOptions {
74+
const env: NodeJS.ProcessEnv = process.env;
75+
env[accessTokenEnvSetting] = env[accessTokenEnvSettingLegacy] = getSystemAccessToken();
76+
return <IExecOptions>{
77+
env: env
78+
};
79+
}
80+
81+
/**
82+
* Configure the JVM associated with this run.
83+
* @param {string} gradleOptions - Gradle options provided by the user
84+
*/
85+
export function setGradleOpts(gradleOptions: string): void {
86+
if (gradleOptions) {
87+
process.env['GRADLE_OPTS'] = gradleOptions;
88+
tl.debug(`GRADLE_OPTS is now set to ${gradleOptions}`);
89+
}
90+
}
91+
92+
export function extractGradleVersion(str: string): string {
93+
const regex = /^Gradle (?<version>\d+\.\d+(?:\.\d+)?.*$)/m;
94+
const match = str.match(regex);
95+
return match?.groups?.version || 'unknown';
96+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import * as fs from 'fs';
2+
import * as os from 'os';
3+
import * as tl from 'azure-pipelines-task-lib/task';
4+
5+
6+
/**
7+
* Configure wrapper script:
8+
* - For Windows - set `*.bat` extension
9+
* - For Linux/macOS - set script as executable
10+
* @param {string} wrapperScript - Relative path from the repository root to the Gradle Wrapper script.
11+
* @returns {string} path to the wrapper script
12+
*/
13+
export function configureWrapperScript(wrapperScript: string): string {
14+
let script: string = wrapperScript;
15+
const isWindows: RegExpMatchArray = os.type().match(/^Win/);
16+
17+
if (isWindows) {
18+
// append .bat extension name on Windows platform
19+
if (!script.endsWith('bat')) {
20+
tl.debug('Append .bat extension name to gradlew script.');
21+
script += '.bat';
22+
}
23+
}
24+
25+
if (fs.existsSync(script)) {
26+
try {
27+
// Make sure the wrapper script is executable
28+
fs.accessSync(script, fs.constants.X_OK)
29+
} catch (err) {
30+
// If not, show warning and chmodding the gradlew file to make it executable
31+
tl.warning(tl.loc('chmodGradlew'));
32+
fs.chmodSync(script, '755');
33+
}
34+
}
35+
return script;
36+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import * as tl from 'azure-pipelines-task-lib/task';
2+
3+
const TESTRUN_SYSTEM = 'VSTS - gradle';
4+
5+
6+
/**
7+
* Publish unit tests results to Azure DevOps
8+
* @param {boolean} publishJUnitResults - if set to `true`, the result of the unit tests will be published otherwise publishing will be skipped
9+
* @param {string} testResultsFiles - pattern for test results files
10+
*/
11+
export function publishTestResults(publishJUnitResults: boolean, testResultsFiles: string): number {
12+
if (publishJUnitResults) {
13+
let matchingTestResultsFiles: string[] = [];
14+
15+
// check for pattern in testResultsFiles
16+
if (testResultsFiles.indexOf('*') >= 0 || testResultsFiles.indexOf('?') >= 0) {
17+
tl.debug('Pattern found in testResultsFiles parameter');
18+
19+
const buildFolder: string = tl.getVariable('System.DefaultWorkingDirectory');
20+
21+
// The find options are as default, except the `skipMissingFiles` option is set to `true`
22+
// so there will be a warning instead of an error if an item will not be found
23+
const findOptions: tl.FindOptions = {
24+
allowBrokenSymbolicLinks: false,
25+
followSpecifiedSymbolicLink: true,
26+
followSymbolicLinks: true,
27+
skipMissingFiles: true
28+
};
29+
30+
matchingTestResultsFiles = tl.findMatch(buildFolder, testResultsFiles, findOptions, { matchBase: true });
31+
} else {
32+
tl.debug('No pattern found in testResultsFiles parameter');
33+
matchingTestResultsFiles = [testResultsFiles];
34+
}
35+
36+
if (!matchingTestResultsFiles || matchingTestResultsFiles.length === 0) {
37+
console.log(tl.loc('NoTestResults', testResultsFiles));
38+
return 0;
39+
}
40+
41+
const tp: tl.TestPublisher = new tl.TestPublisher('JUnit');
42+
const testRunTitle = tl.getInput('testRunTitle');
43+
44+
tp.publish(matchingTestResultsFiles, 'true', '', '', testRunTitle, 'true', TESTRUN_SYSTEM);
45+
}
46+
}

Tasks/GradleV4/Modules/utils.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { ITaskResult, ICodeAnalysisResult } from '../interfaces';
2+
import { TaskResult } from 'azure-pipelines-task-lib';
3+
4+
/**
5+
* Resolve task status based on code analysis run results
6+
* @param {ICodeAnalysisResult} codeAnalysisResult - Code analysis run data
7+
* @returns {ITaskResult} task status and message
8+
*/
9+
export function resolveTaskResult(codeAnalysisResult: ICodeAnalysisResult): ITaskResult {
10+
let status: TaskResult;
11+
let message: string = '';
12+
13+
if (codeAnalysisResult.gradleResult === 0) {
14+
status = TaskResult.Succeeded;
15+
message = 'Build succeeded.';
16+
} else if (codeAnalysisResult.gradleResult === -1) {
17+
status = TaskResult.Failed;
18+
19+
if (codeAnalysisResult.statusFailed) {
20+
message = `Code analysis failed. Gradle exit code: ${codeAnalysisResult.gradleResult}. Error: ${codeAnalysisResult.analysisError}`;
21+
} else {
22+
message = `Build failed. Gradle exit code: ${codeAnalysisResult.gradleResult}`;
23+
}
24+
}
25+
26+
const taskResult: ITaskResult = {
27+
status: status,
28+
message: message
29+
};
30+
31+
return taskResult;
32+
}

Tasks/GradleV4/README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Build your code using Gradle in Azure Pipelines
2+
3+
### Parameters for Gradle build task are explained below
4+
5+
- **Gradle Wrapper :** This is a Required field. The location in the repository of the gradlew wrapper used for the build. Note that on Windows build agents (including the hosted pool), you must use the `gradlew.bat` wrapper. Xplat build agents use the `gradlew` shell script. To Know more [click here](https://docs.gradle.org/current/userguide/gradle_wrapper.html)
6+
7+
- **Options :** Specify any command line options you want to pass to the Gradle wrapper. To know more [click here](https://docs.gradle.org/current/userguide/gradle_command_line.html)
8+
9+
- **Goal(s) :** The task(s) for Gradle to execute. A list of tasks can be taken from `gradlew tasks` issued from a command prompt. To know more [click here](https://docs.gradle.org/current/userguide/tutorial_using_tasks.html)
10+
11+
#### JUnit Test Results
12+
Use the next three options to manage your JUnit test results in Azure Pipelines
13+
14+
- **Publish to Azure Pipelines :** Select this option to publish JUnit Test results produced by the Gradle build to Azure Pipelines/TFS. Each test result file matching `Test Results Files` will be published as a test run in Azure Pipelines.
15+
16+
- **Test Results Files :** This option will appear if you select the above option. Here, provide Test results files path. Wildcards can be used. For example, `**/TEST-*.xml` for all xml files whose name starts with `TEST-."`
17+
18+
- **Test Run Title :** This option will appear if you select the `Publish to Azure Pipelines/TFS` option. Here provide a name for the Test Run
19+
20+
#### Advanced
21+
Use the next options to manage your `JAVA_HOME` attribute by JDK Version and Path
22+
23+
- **Working Directory :** Directory on the build agent where the Gradle wrapper will be invoked from. Defaults to the repository root.
24+
25+
- **Set JAVA_HOME by :** Select to set `JAVA_HOME` either by providing a path or let Azure Pipelines set the `JAVA_HOME` based on JDK version choosen. By default it is set to `JDK Version`
26+
27+
- **JDK Version :** Here provide the PATH to `JAVA_HOME` if you want to set it by path or select the appropriate JDK version.
28+
29+
- **JDK Architecture :** Select the approriate JDK Architecture. By default it is set to `x86`
30+
31+
#### Code Analysis
32+
33+
- **Run SonarQube Analysis :** You can choose to run SonarQube analysis after executing the current goals. 'install' or 'package' goals should be executed first. To know more about this option [click here](https://devblogs.microsoft.com/devops/the-gradle-build-task-now-supports-sonarqube-analysis/)
34+
35+
- **Run Checkstyle :** You can choose to run the Checkstyle static code analysis tool, which checks the compliance of your source code with coding rules. You will receive a code analysis report with the number of violations detected, as well as the original report files if there were any violations.
36+
37+
- **Run PMD :** You can choose to run the PMD static code analysis tool, which examines your source code for possible bugs. You will receive a code analysis report with the number of violations detected, as well as the original report files if there were any violations.
38+
39+
- **Run FindBugs :** You can choose to run the FindBugs static code analysis tool, which examines the bytecode of your program for possible bugs. You will receive a code analysis report with the number of violations detected, as well as the original report files if there were any violations.
40+
41+
### Q&A
42+
43+
#### How do I generate a wrapper from my Gradle project?
44+
45+
The Gradle wrapper allows the build agent to download and configure the exact Gradle environment that is checked into the repository without having any software configuration on the build agent itself other than the JVM.
46+
47+
- **1.** Create the Gradle wrapper by issuing the following command from the root project directory where your build.gradle resides:
48+
`jamal@fabrikam> gradle wrapper`
49+
50+
51+
- **2.** Upload your Gradle wrapper to your remote repository.
52+
53+
There is a binary artifact that is generated by the gradle wrapper (located at `gradle/wrapper/gradle-wrapper.jar`). This binary file is small and doesn't require updating. If you need to change the Gradle configuration run on the build agent, you update the `gradle-wrapper.properties`.
54+
55+
The repository should look something like this:
56+
57+
```ssh
58+
|-- gradle/
59+
`-- wrapper/
60+
`-- gradle-wrapper.jar
61+
`-- gradle-wrapper.properties
62+
|-- src/
63+
|-- .gitignore
64+
|-- build.gradle
65+
|-- gradlew
66+
|-- gradlew.bat
67+
```
68+
69+
70+
71+

0 commit comments

Comments
 (0)