Skip to content

Commit 7b897ac

Browse files
Implemented task.json validation for tfx extension create command (microsoft#477)
* Implemented task.json validation for tfx extension create command * Bump version. Add missing space * Display warnings instead of errors when task.json validation fails during extension creation * Added more info to warning message * Slight code improvements --------- Co-authored-by: v-levockina <undefined>
1 parent 9f0c37e commit 7b897ac

File tree

5 files changed

+41
-15
lines changed

5 files changed

+41
-15
lines changed

app/exec/build/tasks/upload.ts

+2-6
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@ export function getCommand(args: string[]): BuildTaskUpload {
1414

1515
var c_taskJsonFile: string = "task.json";
1616

17-
interface TaskJson {
18-
id: string;
19-
}
20-
2117
export class BuildTaskUpload extends tasksBase.BuildTaskBase<agentContracts.TaskDefinition> {
2218
protected description = "Upload a Build Task.";
2319
protected serverCommand = true;
@@ -46,7 +42,7 @@ export class BuildTaskUpload extends tasksBase.BuildTaskBase<agentContracts.Task
4642

4743
// find task.json inside zip, make sure its there then deserialize content
4844
const fileContent: string = await z.files[c_taskJsonFile].async('text');
49-
const taskJson: TaskJson = JSON.parse(fileContent);
45+
const taskJson: vm.TaskJson = JSON.parse(fileContent);
5046

5147
sourceLocation = taskZipPath;
5248
taskId = taskJson.id;
@@ -57,7 +53,7 @@ export class BuildTaskUpload extends tasksBase.BuildTaskBase<agentContracts.Task
5753
vm.exists(taskPath, "specified directory " + taskPath + " does not exist.");
5854

5955
const taskJsonPath: string = path.join(taskPath, c_taskJsonFile);
60-
const taskJson: TaskJson = await vm.validate(taskJsonPath, "no " + c_taskJsonFile + " in specified directory");
56+
const taskJson: vm.TaskJson = vm.validate(taskJsonPath, "no " + c_taskJsonFile + " in specified directory");
6157

6258
const archive = archiver("zip");
6359
archive.on("error", function(error) {

app/exec/extension/_lib/merger.ts

+30
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import version = require("../../../lib/dynamicVersion");
2424
import { promisify } from "util";
2525
import { readdir, readFile, writeFile, lstat } from "fs";
2626
import { exists } from "../../../lib/fsUtils";
27+
import { validate, TaskJson } from "../../../lib/jsonvalidate";
2728

2829
/**
2930
* Combines the vsix and vso manifests into one object
@@ -163,6 +164,7 @@ export class Merger {
163164
return Promise.all(manifestPromises).then(partials => {
164165
// Determine the targets so we can construct the builders
165166
let targets: TargetDeclaration[] = [];
167+
const taskJsonValidationPromises: Promise<any>[] = [];
166168
partials.forEach(partial => {
167169
if (_.isArray(partial["targets"])) {
168170
targets = targets.concat(partial["targets"]);
@@ -221,6 +223,9 @@ export class Merger {
221223
absolutePath = path.join(path.dirname(partial.__origin), asset.path);
222224
}
223225
asset.path = path.relative(this.settings.root, absolutePath);
226+
227+
const taskJsonPattern: string = path.join(absolutePath, '**', "task.json");
228+
taskJsonValidationPromises.push(this.validateTaskJson(taskJsonPattern));
224229
});
225230
}
226231
// Transform icon paths as above
@@ -280,6 +285,7 @@ export class Merger {
280285
return Promise.all(
281286
[updateVersionPromise].concat(
282287
this.manifestBuilders.map(b => b.finalize(packageFiles, resourceData, this.manifestBuilders)),
288+
taskJsonValidationPromises
283289
),
284290
).then(() => {
285291
// const the composer do validation
@@ -401,4 +407,28 @@ export class Merger {
401407
}
402408
return files;
403409
}
410+
411+
private async validateTaskJson(taskJsonSearchPattern: string): Promise<TaskJson> {
412+
try {
413+
const matches: string[] = await promisify(glob)(taskJsonSearchPattern);
414+
415+
if (matches.length === 0) {
416+
trace.debug(`No task.json file found for validation in ${taskJsonSearchPattern}`);
417+
return;
418+
}
419+
420+
const taskJsonPath = matches[0];
421+
const taskJsonExists = await exists(taskJsonPath);
422+
423+
if (taskJsonExists) {
424+
return validate(taskJsonPath, "no task.json in specified directory");
425+
}
426+
427+
} catch (err) {
428+
const warningMessage = "Please, make sure the task.json file is correct. In the future, this warning will be treated as an error.\n";
429+
trace.warn(err && err instanceof Error
430+
? warningMessage + err.message
431+
: `Error occurred while validating task.json. ${warningMessage}`);
432+
}
433+
}
404434
}

app/lib/jsonvalidate.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
import { defer } from "./promiseUtils";
2-
31
var fs = require("fs");
42
var check = require("validator");
53
var trace = require("./trace");
64

75
const deprecatedRunners = ["Node6", "Node10", "Node16"];
86

7+
export interface TaskJson {
8+
id: string;
9+
}
10+
911
/*
1012
* Checks a json file for correct formatting against some validation function
1113
* @param jsonFilePath path to the json file being validated
1214
* @param jsonValidationFunction function that validates parsed json data against some criteria
1315
* @return the parsed json file
1416
* @throws InvalidDirectoryException if json file doesn't exist, InvalidJsonException on failed parse or *first* invalid field in json
1517
*/
16-
export function validate(jsonFilePath: string, jsonMissingErrorMessage?: string): Promise<any> {
18+
export function validate(jsonFilePath: string, jsonMissingErrorMessage?: string): TaskJson {
1719
trace.debug("Validating task json...");
18-
var deferred = defer<any>();
1920
var jsonMissingErrorMsg: string = jsonMissingErrorMessage || "specified json file does not exist.";
2021
this.exists(jsonFilePath, jsonMissingErrorMsg);
2122

@@ -34,13 +35,12 @@ export function validate(jsonFilePath: string, jsonMissingErrorMessage?: string)
3435
output += "\n\t" + issues[i];
3536
}
3637
trace.debug(output);
37-
deferred.reject(new Error(output));
38+
throw new Error(output);
3839
}
3940

4041
trace.debug("Json is valid.");
4142
validateRunner(taskJson);
42-
deferred.resolve(taskJson);
43-
return <any>deferred.promise;
43+
return taskJson;
4444
}
4545

4646
/*

package-lock.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tfx-cli",
3-
"version": "0.17.0",
3+
"version": "0.18.0",
44
"description": "CLI for Azure DevOps Services and Team Foundation Server",
55
"repository": {
66
"type": "git",

0 commit comments

Comments
 (0)