Skip to content

Commit ec83c35

Browse files
Add Pr check for agent-base (#20195)
* Add Pr check for agent-base - added pr checks for agent-base - added troubleshooting section to the docs * Add Pr check for agent-base - Merged two method in one - Fixed powershell test error
1 parent 70b4018 commit ec83c35

File tree

5 files changed

+121
-21
lines changed

5 files changed

+121
-21
lines changed

ci/after-build-check-tasks.js

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
const util = require('./ci-util');
22
const fs = require('fs');
33
const path = require('path');
4-
var crypto = require('crypto');
4+
const semver = require('semver');
55

66
const fileToJson = util.fileToJson;
77
const buildTasksPath = util.buildTasksPath;
8-
const GITHUB_LINK = 'https://github.com/microsoft/azure-pipelines-tasks/blob/master/docs/migrateNode16.md';
8+
const logToPipeline = util.logToPipeline;
9+
const GITHUB_LINK = 'https://github.com/microsoft/azure-pipelines-tasks/blob/master/docs/validation-errors.md';
910

1011
/**
1112
* Function walking through directories and looking for
@@ -37,17 +38,18 @@ function findLib(dirPath, libRegExp) {
3738

3839
/**
3940
* Function iterates over the given array to find
40-
* which tasks have multiple task lib packages
41-
* @param {Array} scanningTask
41+
* which tasks have package in node_modules
42+
* @param {Array} scanningTask - array of tasks
43+
* @param {RegExp} regExp - regular expression to find package
44+
* @param {Boolean} includeAll - flag to include all founded packages
4245
* @returns Array<Object>
4346
*/
44-
function findWithFsFromPaths(scanningTask) {
47+
function findPackageUsingRegExp(scanningTask, regExp, includeAll = false) {
4548
const foundedTasks = [];
4649
for (let task of scanningTask) {
4750
const taskPath = task.taskPath
48-
const reg = new RegExp('azure-pipelines-task-lib')
49-
const result = findLib(path.join(taskPath, 'node_modules'), reg);
50-
if (result.length > 1) {
51+
const result = findLib(path.join(taskPath, 'node_modules'), regExp);
52+
if ((!includeAll && result.length > 1) || includeAll) {
5153
const foundedPaths = result.map((path) => path.replace(buildTasksPath, ''));
5254
foundedTasks.push({
5355
task: task.taskName,
@@ -75,11 +77,10 @@ function isNodeHandlerExists(taskDefinition) {
7577
}
7678

7779
/**
78-
* Function looking for multiple azure-pipelines-task-lib versions
79-
* in builded tasks, in case if package found multiple times throw error
80-
* Note: now function compares only for tasks which have Node10 and Node16 in their task.json
80+
* Function to get all built tasks
81+
* @returns {Array<Tasks>} - array of tasks with path and versions
8182
*/
82-
function findNonUniqueTaskLib() {
83+
function getBuiltTasks() {
8384
const taskPaths = fs.readdirSync(buildTasksPath, { encoding: 'utf-8' })
8485
const scanningTasks = [];
8586
for (let taskName of taskPaths) {
@@ -105,33 +106,82 @@ function findNonUniqueTaskLib() {
105106
});
106107
}
107108

108-
const haveDependencies = findWithFsFromPaths(scanningTasks);
109+
return scanningTasks;
110+
}
111+
112+
/**
113+
* Function looking for multiple azure-pipelines-task-lib versions
114+
* in builded tasks, in case if package found multiple times throw error
115+
* Note: now function compares only for tasks which have Node10 and Node16 in their task.json
116+
*/
117+
function findNonUniqueTaskLib() {
118+
const taskLibSection = "#findnonuniquetasklib-section"
119+
const scanningTasks = getBuiltTasks();
120+
const reg = new RegExp('azure-pipelines-task-lib')
121+
const haveDependencies = findPackageUsingRegExp(scanningTasks, reg, false);
109122
if (haveDependencies.length > 0) {
110-
console.log(`##vso[task.logissue type=error;sourcepath=ci/check-tasks.js;linenumber=109;]The following tasks have duplicate azure-pipelines-task-lib:
111-
${JSON.stringify(haveDependencies, null, 2)}
112-
Please examine the following link: ${GITHUB_LINK}`);
123+
logToPipeline('error', `The following tasks have duplicate azure-pipelines-task-lib:\n${JSON.stringify(haveDependencies, null, 2)}`);
124+
logToPipeline('error', `Please examine the following link: ${GITHUB_LINK + taskLibSection}`);
113125
process.exit(1);
114126
}
115127

116-
console.log('No duplicates found.');
128+
logToPipeline('info', 'No duplicates found');
117129
return null;
118130
}
119131

120132
function analyzePowershellTasks() {
121133
let output = '';
122134
if (process.platform !== 'win32') {
123-
console.log('The powershell check is only supported on Windows. Skipping...');
135+
logToPipeline('info', 'The powershell check is only supported on Windows. Skipping...');
124136
return;
125137
}
126138

127139
try {
128140
const pwshScriptPath = path.join(__dirname, 'check-powershell-syntax.ps1');
129141
output = util.run(`powershell -NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted ${pwshScriptPath} ${buildTasksPath}`, true);
130142
} catch (e) {
131-
console.log(`##vso[task.logissue type=error;sourcepath=ci/check-tasks.js;linenumber=123;]Please check the tasks, seems like they have invalid PowerShell syntax.`)
143+
logToPipeline('error', 'Please check the tasks, seems like they have invalid PowerShell syntax.');
144+
process.exit(1);
145+
}
146+
}
147+
148+
function findIncompatibleAgentBase() {
149+
const minAgentBaseVersion = '6.0.2';
150+
const agentBaseSection = "#findincompatibleagentbase-section"
151+
const scanningTasks = getBuiltTasks();
152+
const reg = new RegExp('agent-base')
153+
const agentBaseTasks = findPackageUsingRegExp(scanningTasks, reg, true);
154+
const errors = [];
155+
156+
for (const { task, locations } of agentBaseTasks) {
157+
if (!locations.length) continue;
158+
159+
for (const agentBasePath of locations) {
160+
const packagePath = path.join(buildTasksPath, agentBasePath, 'package.json');
161+
if (!fs.existsSync(packagePath)) {
162+
logToPipeline('warning', `The following task has no package.json file: ${task}`);
163+
continue;
164+
}
165+
166+
const agentBaseVersion = fileToJson(packagePath).version;
167+
if (semver.lt(agentBaseVersion, minAgentBaseVersion)) {
168+
errors.push({ task, agentBasePath, agentBaseVersion });
169+
}
170+
}
171+
}
172+
173+
if (errors.length) {
174+
logToPipeline('warning', `The following tasks have incompatible agent-base versions, please use agent-base >= ${minAgentBaseVersion}:\n${JSON.stringify(errors, null, 2)}`);
175+
logToPipeline('error', `Please examine the following link: ${GITHUB_LINK + agentBaseSection}`);
132176
process.exit(1);
133177
}
134178
}
135179

180+
181+
182+
// logToPipeline("section", "Start findNonUniqueTaskLib")
136183
// findNonUniqueTaskLib();
137-
analyzePowershellTasks();
184+
// logToPipeline("section", "Start analyzePowershellTasks")
185+
// analyzePowershellTasks();
186+
logToPipeline("section", "Start findIncompatibleAgentBase")
187+
findIncompatibleAgentBase();

ci/build-all-steps.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ steps:
7575
condition: and(succeeded(), ne(variables['numTasks'], 0))
7676

7777
- script: node ./ci/after-build-check-tasks.js
78-
displayName: Check that tasks has no duplicated libs
78+
displayName: After build tasks validation
7979
condition: |
8080
and(
8181
succeeded(),

ci/check-powershell-syntax.ps1

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ function main() {
115115
(Check-PowershellHandler $_.FullName) -eq $true
116116
}
117117

118+
if ($tasks.Count -eq 0) {
119+
Write-Host "No PowerShell handler found in the tasks."
120+
exit 0;
121+
}
122+
118123
$analyzerResults = Check-Tasks -taskPaths $tasks.FullName;
119124

120125
return $analyzerResults;

ci/ci-util.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,8 @@ function logToPipeline(type, payload) {
564564
case 'debug':
565565
console.log(`##vso[task.debug]${payload}`);
566566
break;
567+
case 'section':
568+
console.log(`##[section]${payload}`);
567569
default:
568570
console.log(payload);
569571
}

docs/validation-errors.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Validation Errors in the pipeline
2+
3+
## findNonUniqueTaskLib section
4+
The check is looking for duplicate usage of [azure-pipelines-task-lib](https://www.npmjs.com/package/azure-pipelines-task-lib).\
5+
The `azure-pipelines-task-lib` was designed as a singleton and there might be errors if the task uses different package versions.
6+
7+
If you have common npm packages as the task dependency, make sure the all dependencies have same version of `azure-pipelines-task-lib` in the task.\
8+
As a possible solution you also can remove these package versions through the `make.json` file, for example:
9+
10+
```json
11+
{
12+
"rm": [
13+
{
14+
"items": [
15+
"node_modules/azure-pipelines-tasks-java-common/node_modules/azure-pipelines-task-lib",
16+
],
17+
"options": "-Rf"
18+
}
19+
]
20+
}
21+
```
22+
23+
## findIncompatibleAgentBase section
24+
The checks will throws error if the [agent-base](https://www.npmjs.com/package/agent-base) package with version below 6.0.2 was found. \
25+
Usually this package comes with `azure-pipelines-tasks-azure-arm-rest` package.
26+
27+
The `agent-base` package below 6.0.2 does not work with node 10+ and the task will fail if the cx will try to use it with proxy. \
28+
To fix the check you need to upgrade it on 6.0.2 at least, for it, please, upgrade your common packages for a new version(if avaiable). \
29+
Another option is to install agent-base v6+ in the task and remove existing one using the `make.json` file using path from the error.
30+
31+
```json
32+
{
33+
"rm": [
34+
{
35+
"items": [
36+
"node_modules/https-proxy-agent/node_modules/agent-base",
37+
"node_modules/azure-pipelines-tasks-azure-arm-rest/node_modules/agent-base"
38+
],
39+
"options": "-Rf"
40+
}
41+
]
42+
}
43+
```

0 commit comments

Comments
 (0)