Skip to content

Commit 4bfe4eb

Browse files
Merge pull request #332 from microsoft/users/stfrance/task-zip-upload
Add ability to upload a task zip.
2 parents b457fe3 + 05dcf3d commit 4bfe4eb

File tree

7 files changed

+250
-229
lines changed

7 files changed

+250
-229
lines changed

app/exec/build/tasks/create.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { TfCommand } from "../../../lib/tfcommand";
21
import check = require("validator");
3-
import common = require("../../../lib/common");
42
import fs = require("fs");
53

64
import path = require("path");

app/exec/build/tasks/default.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { TfCommand, CoreArguments } from "../../../lib/tfcommand";
21
import args = require("../../../lib/arguments");
32
import buildBase = require("../default");
43

@@ -26,7 +25,8 @@ export class BuildTaskBase<T> extends buildBase.BuildBase<TaskArguments, T> {
2625

2726
this.registerCommandArgument("all", "All Tasks?", "Get all build tasks.", args.BooleanArgument, "false");
2827
this.registerCommandArgument("taskId", "Task ID", "Identifies a particular Build Task.", args.StringArgument);
29-
this.registerCommandArgument("taskPath", "Task path", "Local path to a Build Task.", args.ExistingDirectoriesArgument);
28+
this.registerCommandArgument("taskPath", "Task path", "Local path to a Build Task.", args.ExistingDirectoriesArgument, null);
29+
this.registerCommandArgument("taskZipPath", "Task zip path", "Local path to an already zipped task", args.StringArgument, null);
3030
this.registerCommandArgument("overwrite", "Overwrite?", "Overwrite existing Build Task.", args.BooleanArgument, "false");
3131

3232
this.registerCommandArgument("taskName", "Task Name", "Name of the Build Task.", args.StringArgument);

app/exec/build/tasks/delete.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { TfCommand } from "../../../lib/tfcommand";
21
import agentContracts = require("azure-devops-node-api/interfaces/TaskAgentInterfaces");
3-
import args = require("../../../lib/arguments");
42
import tasksBase = require("./default");
53
import trace = require("../../../lib/trace");
64

app/exec/build/tasks/list.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { TfCommand } from "../../../lib/tfcommand";
21
import agentContracts = require("azure-devops-node-api/interfaces/TaskAgentInterfaces");
3-
import args = require("../../../lib/arguments");
42
import tasksBase = require("./default");
53
import trace = require("../../../lib/trace");
64

app/exec/build/tasks/upload.ts

Lines changed: 59 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,85 @@
1-
import { TfCommand } from "../../../lib/tfcommand";
21
import agentContracts = require("azure-devops-node-api/interfaces/TaskAgentInterfaces");
32
import archiver = require("archiver");
4-
import args = require("../../../lib/arguments");
53
import fs = require("fs");
64
import path = require("path");
75
import tasksBase = require("./default");
86
import trace = require("../../../lib/trace");
97
import vm = require("../../../lib/jsonvalidate");
8+
import { ITaskAgentApi } from "azure-devops-node-api/TaskAgentApi";
9+
import zip = require("jszip");
1010

1111
export function getCommand(args: string[]): BuildTaskUpload {
1212
return new BuildTaskUpload(args);
1313
}
1414

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

17+
interface TaskJson {
18+
id: string;
19+
}
20+
1721
export class BuildTaskUpload extends tasksBase.BuildTaskBase<agentContracts.TaskDefinition> {
1822
protected description = "Upload a Build Task.";
1923
protected serverCommand = true;
2024

2125
protected getHelpArgs(): string[] {
22-
return ["taskPath", "overwrite"];
26+
return ["taskPath", "taskZipPath", "overwrite"];
2327
}
2428

2529
public async exec(): Promise<agentContracts.TaskDefinition> {
26-
return this.commandArgs.taskPath.val().then(taskPaths => {
27-
let taskPath = taskPaths[0];
28-
return this.commandArgs.overwrite.val().then<agentContracts.TaskDefinition>(overwrite => {
29-
vm.exists(taskPath, "specified directory " + taskPath + " does not exist.");
30-
//directory is good, check json
31-
32-
let tp = path.join(taskPath, c_taskJsonFile);
33-
return vm.validate(tp, "no " + c_taskJsonFile + " in specified directory").then(async taskJson => {
34-
let archive = archiver("zip");
35-
archive.on("error", function(error) {
36-
trace.debug("Archiving error: " + error.message);
37-
error.message = "Archiving error: " + error.message;
38-
throw error;
39-
});
40-
archive.directory(path.resolve(taskPath), false);
41-
42-
const collectionUrl = this.connection.getCollectionUrl();
43-
console.log("Collection URL: " + collectionUrl);
44-
let agentApi = await this.webApi.getTaskAgentApi(collectionUrl);
45-
46-
archive.finalize();
47-
return agentApi.uploadTaskDefinition(null, <any>archive, taskJson.id, overwrite).then(() => {
48-
trace.debug("Success");
49-
return <agentContracts.TaskDefinition>{
50-
sourceLocation: taskPath,
51-
};
52-
});
53-
});
30+
const taskPaths = await this.commandArgs.taskPath.val();
31+
const taskZipPath = await this.commandArgs.taskZipPath.val();
32+
const overwrite = await this.commandArgs.overwrite.val();
33+
34+
let taskStream: NodeJS.ReadableStream = null;
35+
let taskId: string = null;
36+
let sourceLocation: string = null;
37+
38+
if (!taskZipPath && !taskPaths) {
39+
throw new Error("You must specify either --task-path or --task-zip-path.");
40+
}
41+
42+
if (taskZipPath) {
43+
// User provided an already zipped task, upload that.
44+
const data: Buffer = fs.readFileSync(taskZipPath);
45+
const z: zip = await zip.loadAsync(data);
46+
47+
// find task.json inside zip, make sure its there then deserialize content
48+
const fileContent: string = await z.files[c_taskJsonFile].async('text');
49+
const taskJson: TaskJson = JSON.parse(fileContent);
50+
51+
sourceLocation = taskZipPath;
52+
taskId = taskJson.id;
53+
taskStream = z.generateNodeStream();
54+
} else {
55+
// User provided the path to a directory with the task content
56+
const taskPath: string = taskPaths[0];
57+
vm.exists(taskPath, "specified directory " + taskPath + " does not exist.");
58+
59+
const taskJsonPath: string = path.join(taskPath, c_taskJsonFile);
60+
const taskJson: TaskJson = await vm.validate(taskJsonPath, "no " + c_taskJsonFile + " in specified directory");
61+
62+
const archive = archiver("zip");
63+
archive.on("error", function(error) {
64+
trace.debug("Archiving error: " + error.message);
65+
error.message = "Archiving error: " + error.message;
66+
throw error;
5467
});
55-
});
68+
archive.directory(path.resolve(taskPath), false);
69+
archive.finalize();
70+
71+
sourceLocation = taskPath;
72+
taskId = taskJson.id;
73+
taskStream = archive;
74+
}
75+
76+
const collectionUrl: string = this.connection.getCollectionUrl();
77+
trace.info("Collection URL: " + collectionUrl);
78+
const agentApi: ITaskAgentApi = await this.webApi.getTaskAgentApi(collectionUrl);
79+
80+
await agentApi.uploadTaskDefinition(null, taskStream, taskId, overwrite);
81+
trace.debug("Success");
82+
return <agentContracts.TaskDefinition> { sourceLocation: sourceLocation, };
5683
}
5784

5885
public friendlyOutput(data: agentContracts.TaskDefinition): void {

0 commit comments

Comments
 (0)