Skip to content

Commit aab9dd2

Browse files
Copilotsanjuyadav24
andcommitted
Add feature flag for zipAfterPublish directory creation behavior
Co-authored-by: sanjuyadav24 <[email protected]>
1 parent f3399b1 commit aab9dd2

File tree

5 files changed

+128
-3
lines changed

5 files changed

+128
-3
lines changed

Tasks/DotNetCoreCLIV2/Tests/L0.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,18 @@ describe('DotNetCoreExe Suite', function () {
333333
assert(tr.succeeded, 'task should have succeeded');
334334
});
335335

336+
it('publish works with zipAfterPublish and legacy directory creation option', async () => {
337+
process.env["__projects__"] = "web/project.json";
338+
process.env["__publishWebProjects__"] = "false";
339+
process.env["__arguments__"] = "--configuration release --output /usr/out";
340+
let tp = path.join(__dirname, 'zipAfterPublishLegacyTests.js');
341+
let tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp);
342+
await tr.runAsync();
343+
344+
assert(tr.invokedToolCount == 1, 'should have invoked tool once');
345+
assert(tr.succeeded, 'task should have succeeded');
346+
});
347+
336348
it('publish fails with zipAfterPublish and publishWebProjects option with no project file specified', async () => {
337349
process.env["__projects__"] = "";
338350
process.env["__publishWebProjects__"] = "false";
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import ma = require('azure-pipelines-task-lib/mock-answer');
2+
import tmrm = require('azure-pipelines-task-lib/mock-run');
3+
import path = require('path');
4+
import fs = require('fs');
5+
import assert = require('assert');
6+
7+
let taskPath = path.join(__dirname, '..', 'dotnetcore.js');
8+
let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);
9+
10+
tmr.setInput('command', "publish");
11+
tmr.setInput('projects', "web/project.json");
12+
tmr.setInput('publishWebProjects', "false");
13+
tmr.setInput('arguments', "--configuration release --output /usr/out");
14+
tmr.setInput('zipAfterPublish', "true");
15+
tmr.setInput('modifyOutputPath', "false");
16+
tmr.setInput('zipAfterPublishCreateDirectory', "true"); // Test legacy behavior with directory creation
17+
18+
// Mock file system operations for testing zip functionality
19+
const mockFs = {
20+
createWriteStream: function(filePath) {
21+
console.log("Creating write stream for: " + filePath);
22+
const events = {};
23+
return {
24+
on: (event, callback) => {
25+
events[event] = callback;
26+
return this;
27+
},
28+
end: () => {
29+
console.log("Closing write stream for: " + filePath);
30+
events['close']();
31+
}
32+
};
33+
},
34+
mkdirSync: function(p) {
35+
console.log("Creating directory: " + p);
36+
},
37+
renameSync: function(oldPath, newPath) {
38+
console.log("Moving file from: " + oldPath + " to: " + newPath);
39+
},
40+
existsSync: function(filePath) {
41+
return true;
42+
},
43+
readFileSync: function() {
44+
return "";
45+
},
46+
statSync: function() {
47+
return {
48+
isFile: () => false,
49+
isDirectory: () => true
50+
};
51+
},
52+
lstatSync: function() {
53+
return {
54+
isDirectory: () => true
55+
};
56+
}
57+
};
58+
59+
// Mock archiver
60+
const mockArchiver = function() {
61+
return {
62+
pipe: function() { return this; },
63+
directory: function() { return this; },
64+
finalize: function() { return this; }
65+
};
66+
};
67+
68+
let a: ma.TaskLibAnswers = <ma.TaskLibAnswers>{
69+
"which": { "dotnet": "dotnet" },
70+
"checkPath": { "dotnet": true },
71+
"exist": {
72+
"/usr/out": true
73+
},
74+
"exec": {
75+
"dotnet publish web/project.json --configuration release --output /usr/out": {
76+
"code": 0,
77+
"stdout": "published web without adding project name to path\n",
78+
"stderr": ""
79+
}
80+
},
81+
"findMatch": {
82+
"web/project.json": ["web/project.json"]
83+
},
84+
"rmRF": {
85+
"/usr/out": {
86+
"success": true
87+
}
88+
}
89+
};
90+
91+
tmr.setAnswers(a);
92+
tmr.registerMock('fs', Object.assign({}, fs, mockFs));
93+
tmr.registerMock('archiver', mockArchiver);
94+
tmr.registerMock('azure-pipelines-task-lib/toolrunner', require('azure-pipelines-task-lib/mock-toolrunner'));
95+
96+
tmr.run();

Tasks/DotNetCoreCLIV2/Tests/zipAfterPublishTests.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ tmr.setInput('publishWebProjects', "false");
1313
tmr.setInput('arguments', "--configuration release --output /usr/out");
1414
tmr.setInput('zipAfterPublish', "true");
1515
tmr.setInput('modifyOutputPath', "false");
16+
tmr.setInput('zipAfterPublishCreateDirectory', "false"); // Test new simplified behavior
1617

1718
// Mock file system operations for testing zip functionality
1819
const mockFs = {

Tasks/DotNetCoreCLIV2/dotnetcore.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export class dotNetExe {
2828
private arguments: string;
2929
private publishWebProjects: boolean;
3030
private zipAfterPublish: boolean;
31+
private zipAfterPublishCreateDirectory: boolean;
3132
private outputArgument: string = "";
3233
private outputArgumentIndex: number = 0;
3334
private workingDirectory: string;
@@ -39,6 +40,7 @@ export class dotNetExe {
3940
this.arguments = tl.getInput("arguments", false) || "";
4041
this.publishWebProjects = tl.getBoolInput("publishWebProjects", false);
4142
this.zipAfterPublish = tl.getBoolInput("zipAfterPublish", false);
43+
this.zipAfterPublishCreateDirectory = tl.getBoolInput("zipAfterPublishCreateDirectory", true);
4244
this.workingDirectory = tl.getPathInput("workingDirectory", false);
4345
}
4446

@@ -286,9 +288,14 @@ export class dotNetExe {
286288
var outputTarget = outputSource + ".zip";
287289
await this.zip(outputSource, outputTarget);
288290
tl.rmRF(outputSource);
289-
// When moveZipToOutputSource is true and zipAfterPublish is true,
290-
// we should leave the zip file where it was created and not move it into a subdirectory
291-
// This way the artifact will be the zip file directly instead of a directory containing the zip
291+
292+
// Check if we should create directory for ZIP output (legacy behavior)
293+
if (moveZipToOutputSource && this.zipAfterPublishCreateDirectory) {
294+
// Legacy behavior: create directory and move ZIP file into it
295+
fs.mkdirSync(outputSource);
296+
fs.renameSync(outputTarget, path.join(outputSource, path.basename(outputTarget)));
297+
}
298+
// If zipAfterPublishCreateDirectory is false, leave ZIP file at original location (new simplified behavior)
292299
}
293300
else {
294301
throw tl.loc("noPublishFolderFoundToZip", projectFile);

Tasks/DotNetCoreCLIV2/task.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,15 @@
179179
"required": false,
180180
"helpMarkDown": "If true, folders created by the publish command will have project's folder name prefixed to their folder names when output path is specified explicitly in arguments. This is useful if you want to publish multiple projects to the same folder."
181181
},
182+
{
183+
"name": "zipAfterPublishCreateDirectory",
184+
"type": "boolean",
185+
"visibleRule": "command = publish && zipAfterPublish = true",
186+
"label": "Create directory for ZIP output",
187+
"defaultValue": "true",
188+
"required": false,
189+
"helpMarkDown": "If true, the ZIP file will be placed in a directory with the same name as the output path (legacy behavior). If false, the ZIP file will remain at the original output location (simplified behavior)."
190+
},
182191
{
183192
"name": "selectOrConfig",
184193
"aliases": [

0 commit comments

Comments
 (0)