async function execBuild()

in Tasks/MavenV2/maventask.ts [123:295]


async function execBuild() {
    // Maven task orchestration occurs as follows:
    // 1. Check that Maven exists by executing it to retrieve its version.
    // 2. Apply any goals for static code analysis tools selected by the user.
    // 3. Run Maven. Compilation or test errors will cause this to fail.
    //    In case the build has failed, the analysis will still succeed but the report will have less data. 
    // 4. Attempt to collate and upload static code analysis build summaries and artifacts.
    // 5. Always publish test results even if tests fail, causing this task to fail.
    // 6. If #3 or #4 above failed, exit with an error code to mark the entire step as failed.

    ccReportTask = await execEnableCodeCoverage();
    var userRunFailed: boolean = false;
    var codeAnalysisFailed: boolean = false;

    // Setup tool runner that executes Maven only to retrieve its version
    var mvnGetVersion = tl.tool(mvnExec);
    mvnGetVersion.arg('-version');

    configureMavenOpts();

    // 1. Check that Maven exists by executing it to retrieve its version.
    let settingsXmlFile: string = null;
    await mvnGetVersion.exec()
        .fail(function (err) {
            console.error("Maven is not installed on the agent");
            tl.setResult(tl.TaskResult.Failed, "Build failed."); // tl.exit sets the step result but does not stop execution
            process.exit(1);
        })
        .then(function (code) {
            // Setup tool runner to execute Maven goals
            if (authenticateFeed) {
                var mvnRun = tl.tool(mvnExec);
                mvnRun.arg('-f');
                mvnRun.arg(mavenPOMFile);
                mvnRun.arg('help:effective-pom');
                if(mavenOptions) {
                    mvnRun.line(mavenOptions);
                }
                return util.collectFeedRepositoriesFromEffectivePom(mvnRun.execSync()['stdout'])
                .then(function (repositories) {
                    if (!repositories || !repositories.length) {
                        tl.debug('No built-in repositories were found in pom.xml');
                        util.publishMavenInfo(tl.loc('AuthenticationNotNecessary'));
                        return Q.resolve(true);
                    }
                    tl.debug('Repositories: ' + JSON.stringify(repositories));
                    let mavenFeedInfo:string = '';
                    for (let i = 0; i < repositories.length; ++i) {
                        if (repositories[i].id) {
                            mavenFeedInfo = mavenFeedInfo.concat(tl.loc('UsingAuthFeed')).concat(repositories[i].id + '\n');
                        }
                    }
                    util.publishMavenInfo(mavenFeedInfo);

                    settingsXmlFile = path.join(tl.getVariable('Agent.TempDirectory'), 'settings.xml');
                    tl.debug('checking to see if there are settings.xml in use');
                    let options: RegExpMatchArray = mavenOptions ? mavenOptions.match(/([^" ]*("([^"\\]*(\\.[^"\\]*)*)")[^" ]*)|[^" ]+/g) : undefined;
                    if (options) {
                        mavenOptions = '';
                        for (let i = 0; i < options.length; ++i) {
                            if ((options[i] === '--settings' || options[i] === '-s') && (i + 1) < options.length) {
                                i++; // increment to the file name
                                let suppliedSettingsXml: string = path.resolve(tl.cwd(), options[i]);
                                // Avoid copying settings file to itself
                                if (path.relative(suppliedSettingsXml, settingsXmlFile) !== '') {
                                    tl.cp(suppliedSettingsXml, settingsXmlFile, '-f');
                                } else {
                                    tl.debug('Settings file is already in the correct location. Copying skipped.');    
                                }
                                tl.debug('using settings file: ' + settingsXmlFile);
                            } else {
                                if (mavenOptions) {
                                    mavenOptions = mavenOptions.concat(' ');
                                }
                                mavenOptions = mavenOptions.concat(options[i]);
                            }
                        }
                    }
                    return util.mergeCredentialsIntoSettingsXml(settingsXmlFile, repositories);
                })
                .catch(function (err) {
                    return Q.reject(err);
                });
            } else {
                tl.debug('Built-in Maven feed authentication is disabled');
                return Q.resolve(true);
            }
        })
        .fail(function (err) {
            tl.error(err.message);
            userRunFailed = true; // Record the error and continue
        })
        .then(function (code) {
            // Setup tool runner to execute Maven goals
            var mvnRun = tl.tool(mvnExec);
            mvnRun.arg('-f');
            mvnRun.arg(mavenPOMFile);
            if (settingsXmlFile) {
                mvnRun.arg('-s');
                mvnRun.arg(settingsXmlFile);
            }
            mvnRun.line(mavenOptions);
            if (isCodeCoverageOpted && mavenGoals.indexOf('clean') == -1) {
                mvnRun.arg('clean');
            }
            mvnRun.arg(mavenGoals);

            // 2. Apply any goals for static code analysis tools selected by the user.
            mvnRun = applySonarQubeArgs(mvnRun, execFileJacoco);
            mvnRun = codeAnalysisOrchestrator.configureBuild(mvnRun);

            // Read Maven standard output
            mvnRun.on('stdout', function (data) {
                processMavenOutput(data);
            });

            // 3. Run Maven. Compilation or test errors will cause this to fail.
            return mvnRun.exec(util.getExecOptions());
        })
        .fail(function (err) {
            console.error(err.message);
            userRunFailed = true; // Record the error and continue
        })
        .then(function (code: any) {
            if (code && code['code'] != 0) {
                userRunFailed = true;
            }
            // 4. Attempt to collate and upload static code analysis build summaries and artifacts.

            // The files won't be created if the build failed, and the user should probably fix their build first.
            if (userRunFailed) {
                console.error('Could not retrieve code analysis results - Maven run failed.');
                return;
            }

            // Otherwise, start uploading relevant build summaries.
            tl.debug('Processing code analysis results');
            return codeAnalysisOrchestrator.publishCodeAnalysisResults();
        })
        .fail(function (err) {
            console.error(err.message);
            // Looks like: "Code analysis failed."
            console.error(tl.loc('codeAnalysis_ToolFailed', 'Code'));
            codeAnalysisFailed = true;
        })
        .then(function () {
            // 5. Always publish test results even if tests fail, causing this task to fail.
            if (publishJUnitResults == 'true') {
                publishJUnitTestResults(testResultsFiles);
            }
            publishCodeCoverage(isCodeCoverageOpted).then(function() {
                tl.debug('publishCodeCoverage userRunFailed=' + userRunFailed);

                // 6. If #3 or #4 above failed, exit with an error code to mark the entire step as failed.
                if (userRunFailed || codeAnalysisFailed || codeCoverageFailed) {
                    tl.setResult(tl.TaskResult.Failed, "Build failed."); // Set task failure
                }
                else {
                    tl.setResult(tl.TaskResult.Succeeded, "Build Succeeded."); // Set task success
                }
            })
            .fail(function (err) {
                tl.setResult(tl.TaskResult.Failed, "Build failed."); // Set task failure
            });

            // Do not force an exit as publishing results is async and it won't have finished 
        })
        .fail(function (err) {
            // Set task failure if get exception at step 5
            console.error(err.message);
            tl.setResult(tl.TaskResult.Failed, "Build failed.");
        });
}