Skip to content

Commit 75d54f7

Browse files
[CI/CD] Add task validation step (#18775)
- Added check for validating sources and generated tasks - Added log method for printing errors
1 parent 30577db commit 75d54f7

File tree

5 files changed

+110
-9
lines changed

5 files changed

+110
-9
lines changed

ci/check-tasks.js renamed to ci/after-build-check-tasks.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,4 @@ function findNonUniqueTaskLib() {
115115
console.log('No duplicates found.');
116116
return null;
117117
}
118-
119118
findNonUniqueTaskLib();

ci/before-build-check-tasks.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
const util = require('./ci-util');
2+
const fs = require('fs');
3+
const path = require('path');
4+
5+
const argv = require('minimist')(process.argv.slice(2));
6+
const { genTaskPath, tasksSourcePath, makeOptionPath, logToPipeline } = require('./ci-util');
7+
8+
/**
9+
* Function validating that all passed tasks are presented in tasks folder
10+
* @param {Array<Tasks>} taskList
11+
* @returns {Array<Tasks>} - array of messages which are not presented in tasks folder
12+
*/
13+
function validateTaskSources( taskList ) {
14+
const errorList = [];
15+
16+
for (const task of taskList) {
17+
const taskPath = path.join(tasksSourcePath, task);
18+
if (!fs.existsSync(taskPath)) {
19+
errorList.push(`Sources for ${task} task not found in ${tasksSourcePath} but the task found in ${makeOptionPath}`);
20+
continue;
21+
}
22+
}
23+
24+
return errorList;
25+
}
26+
27+
/**
28+
* Function validating that for all generated task has versionmap file
29+
* @param {Object} makeOptionJson - make-options.json as object
30+
* @returns {Array<String>} - array of messages with tasks which don't have versionmap file
31+
*/
32+
function validateGeneratedTasksExists( makeOptionJson ) {
33+
const excludedKeys = ['tasks', 'taskResources'];
34+
const errorList = [];
35+
36+
for (const key in makeOptionJson) {
37+
if (excludedKeys.includes(key)) continue;
38+
if (!Array.isArray(makeOptionJson[key])) continue;
39+
40+
const taskList = makeOptionJson[key];
41+
for (const task of taskList) {
42+
const versionMapFile = `${task}.versionmap.txt`;
43+
if (fs.existsSync(path.join(genTaskPath, versionMapFile))) continue;
44+
errorList.push(`Task ${task} doesn't have versionmap file but found in ${key} section in make-options.json`);
45+
}
46+
}
47+
return errorList;
48+
}
49+
50+
/**
51+
* Function validating that all tasks presented in make-options.json are valid
52+
*/
53+
function validateMakeOption() {
54+
if (!fs.existsSync(makeOptionPath)) {
55+
throw new Error(`make-options.json doesn't exist in ${makeOptionPath}`);
56+
}
57+
58+
const makeOptions = JSON.parse(fs.readFileSync(makeOptionPath, { encoding: 'utf-8' }));
59+
const messages = [
60+
...validateGeneratedTasksExists(makeOptions),
61+
...validateTaskSources(makeOptions.tasks)
62+
];
63+
64+
if (messages.length > 0) {
65+
console.warn(`\nProblems with ${messages.length} task(s) should be resolved:\n`);
66+
67+
messages.forEach((message) => {
68+
logToPipeline("error", message);
69+
});
70+
71+
process.exit(1);
72+
}
73+
}
74+
75+
validateMakeOption();

ci/build-all-steps.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ steps:
5555
PACKAGE_ENDPOINT: $(Package.Endpoint)
5656
PACKAGE_TOKEN: $(Package.Token)
5757

58+
- script: node ./ci/before-build-check-tasks.js
59+
displayName: Check that tasks has no duplicated libs
60+
condition: and(succeeded(), eq(variables['build.reason'], 'PullRequest'), ne(variables['numTasks'], 0))
61+
5862
- script: node ./ci/check-downgrading.js --task "$(task_pattern)" --sprint $(currentSprint) --week $(currentSprintWeek)
5963
displayName: Check for downgrading tasks
6064
condition: |
@@ -84,7 +88,7 @@ steps:
8488
displayName: Build Tasks
8589
condition: and(succeeded(), ne(variables['numTasks'], 0))
8690

87-
- script: node ./ci/check-tasks.js
91+
- script: node ./ci/after-build-check-tasks.js
8892
displayName: Check that tasks has no duplicated libs
8993
condition: and(succeeded(), eq(variables['build.reason'], 'PullRequest'), ne(variables['numTasks'], 0))
9094

ci/check-downgrading.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ const {
55
} = require('fs');
66
const { mkdir, rm } = require('shelljs');
77
const { platform } = require('os');
8-
const { run, resolveTaskList } = require('./ci-util');
8+
const { run, resolveTaskList, logToPipeline } = require('./ci-util');
99
const { eq, inc, parse, lte, neq } = require('semver');
1010

1111
const taskVersionBumpingDocUrl = "https://aka.ms/azp-tasks-version-bumping";
1212

1313
const packageEndpoint = process.env['PACKAGE_VERSIONS_ENDPOINT'];
1414

1515
if (!packageEndpoint) {
16-
console.log('##vso[task.logissue type=error]Failed to get info from package endpoint because no endpoint was specified. Try setting the PACKAGE_VERSIONS_ENDPOINT environment variable.');
16+
logToPipeline('error', 'Failed to get info from package endpoint because no endpoint was specified. Try setting the PACKAGE_VERSIONS_ENDPOINT environment variable.')
1717
process.exit(1);
1818
}
1919

@@ -120,7 +120,7 @@ function getTasksVersions(tasks, basepath) {
120120
const taskJSONPath = join(basepath, 'Tasks' , x, 'task.json');
121121

122122
if (!existsSync(taskJSONPath)) {
123-
console.log(`##vso[task.logissue type=error]Task.json of ${x} does not exist by path ${taskJSONPath}`);
123+
logToPipeline('error', `Task.json of ${x} does not exist by path ${taskJSONPath}`);
124124
process.exit(1);
125125
}
126126

@@ -142,7 +142,7 @@ async function clientWrapper(url) {
142142
try {
143143
return await client.get(url);
144144
} catch (error) {
145-
console.log(`##vso[task.logissue type=error]Cannot access to ${url} due to error ${error}`);
145+
logToPipeline('error', `Cannot access to ${url} due to error ${error}`);
146146
process.exit(1);
147147
}
148148
}
@@ -151,7 +151,7 @@ async function getFeedTasksVersions() {
151151
const { result, statusCode } = await clientWrapper(packageEndpoint);
152152

153153
if (statusCode !== 200) {
154-
console.log(`##vso[task.logissue type=error]Failed while fetching feed versions.\nStatus code: ${statusCode}\nResult: ${result}`);
154+
logToPipeline('error', `Failed while fetching feed versions.\nStatus code: ${statusCode}\nResult: ${result}`);
155155
process.exit(1);
156156
}
157157

@@ -203,7 +203,7 @@ function compareLocalTaskLoc(localTasks) {
203203
const taskLocJSONPath = join(__dirname, '..', 'Tasks' , localTask.name, 'task.loc.json');
204204

205205
if (!existsSync(taskLocJSONPath)) {
206-
console.log(`##vso[task.logissue type=error]Task.json of ${localTask.name} does not exist by path ${taskLocJSONPath}`);
206+
logToPipeline('error', `Task.json of ${localTask.name} does not exist by path ${taskLocJSONPath}`);
207207
process.exit(1);
208208
}
209209

@@ -248,7 +248,7 @@ async function main({ task, sprint, week }) {
248248
console.warn(`\nProblems with ${messages.length} task(s) should be resolved:\n`);
249249

250250
for (const message of messages) {
251-
console.log(`##vso[task.logissue type=${message.type}]${message.payload}`);
251+
logToPipeline(message.type, message.payload);
252252
}
253253

254254
console.log('\nor you might have an outdated branch, try to merge/rebase your branch from master');

ci/ci-util.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ var aggregateNuspecPath = path.join(packagePath, 'Mseng.MS.TF.Build.Tasks.nuspec
2929
var publishLayoutPath = path.join(packagePath, 'publish-layout');
3030
var publishPushCmdPath = path.join(packagePath, 'publish-layout', 'push.cmd');
3131
var genTaskPath = path.join(__dirname, '..', '_generated');
32+
var makeOptionPath = path.join(__dirname, '..', 'make-options.json');
3233

3334
exports.buildTasksPath = buildTasksPath;
3435
exports.packagePath = packagePath;
@@ -50,6 +51,7 @@ exports.aggregateNuspecPath = aggregateNuspecPath;
5051
exports.publishLayoutPath = publishLayoutPath;
5152
exports.publishPushCmdPath = publishPushCmdPath;
5253
exports.genTaskPath = genTaskPath;
54+
exports.makeOptionPath = makeOptionPath;
5355

5456
//------------------------------------------------------------------------------
5557
// generic functions
@@ -493,3 +495,24 @@ var resolveTaskList = function(taskPattern) {
493495
return taskList;
494496
}
495497
exports.resolveTaskList = resolveTaskList;
498+
499+
/**
500+
* @param {string} type - log type
501+
* @param {string} payload - log message
502+
*/
503+
function logToPipeline(type, payload) {
504+
if (!payload) throw new Error('payload are required');
505+
506+
switch (type) {
507+
case 'error':
508+
case 'warning':
509+
console.log(`##vso[task.logissue type=${type}]${payload}`);
510+
break;
511+
case 'debug':
512+
console.log(`##vso[task.debug]${payload}`);
513+
break;
514+
default:
515+
console.log(payload);
516+
}
517+
}
518+
exports.logToPipeline = logToPipeline;

0 commit comments

Comments
 (0)