Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions Tasks/DotNetCoreCLIV2/Tests/L0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,16 @@ describe('DotNetCoreExe Suite', function () {
assert(tr.succeeded, 'task should have succeeded');
});

it('publish works with zipAfterPublish option', () => {
// TODO
it('publish works with zipAfterPublish option', async () => {
process.env["__projects__"] = "web/project.json";
process.env["__publishWebProjects__"] = "false";
process.env["__arguments__"] = "--configuration release --output /usr/out";
let tp = path.join(__dirname, 'zipAfterPublishTests.js');
let tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp);
await tr.runAsync();

assert(tr.invokedToolCount == 1, 'should have invoked tool once');
assert(tr.succeeded, 'task should have succeeded');
});

it('publish fails with zipAfterPublish and publishWebProjects option with no project file specified', async () => {
Expand Down
95 changes: 95 additions & 0 deletions Tasks/DotNetCoreCLIV2/Tests/zipAfterPublishTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import ma = require('azure-pipelines-task-lib/mock-answer');
import tmrm = require('azure-pipelines-task-lib/mock-run');
import path = require('path');
import fs = require('fs');
import assert = require('assert');

let taskPath = path.join(__dirname, '..', 'dotnetcore.js');
let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);

tmr.setInput('command', "publish");
tmr.setInput('projects', "web/project.json");
tmr.setInput('publishWebProjects', "false");
tmr.setInput('arguments', "--configuration release --output /usr/out");
tmr.setInput('zipAfterPublish', "true");
tmr.setInput('modifyOutputPath', "false");

// Mock file system operations for testing zip functionality
const mockFs = {
createWriteStream: function(filePath) {
console.log("Creating write stream for: " + filePath);
const events = {};
return {
on: (event, callback) => {
events[event] = callback;
return this;
},
end: () => {
console.log("Closing write stream for: " + filePath);
events['close']();
}
};
},
mkdirSync: function(p) {
console.log("Creating directory: " + p);
},
renameSync: function(oldPath, newPath) {
console.log("Moving file from: " + oldPath + " to: " + newPath);
},
existsSync: function(filePath) {
return true;
},
readFileSync: function() {
return "";
},
statSync: function() {
return {
isFile: () => false,
isDirectory: () => true
};
},
lstatSync: function() {
return {
isDirectory: () => true
};
}
};

// Mock archiver
const mockArchiver = function() {
return {
pipe: function() { return this; },
directory: function() { return this; },
finalize: function() { return this; }
};
};

let a: ma.TaskLibAnswers = <ma.TaskLibAnswers>{
"which": { "dotnet": "dotnet" },
"checkPath": { "dotnet": true },
"exist": {
"/usr/out": true
},
"exec": {
"dotnet publish web/project.json --configuration release --output /usr/out": {
"code": 0,
"stdout": "published web without adding project name to path\n",
"stderr": ""
}
},
"findMatch": {
"web/project.json": ["web/project.json"]
},
"rmRF": {
"/usr/out": {
"success": true
}
}
};

tmr.setAnswers(a);
tmr.registerMock('fs', Object.assign({}, fs, mockFs));
tmr.registerMock('archiver', mockArchiver);
tmr.registerMock('azure-pipelines-task-lib/toolrunner', require('azure-pipelines-task-lib/mock-toolrunner'));

tmr.run();
7 changes: 3 additions & 4 deletions Tasks/DotNetCoreCLIV2/dotnetcore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,10 +286,9 @@ export class dotNetExe {
var outputTarget = outputSource + ".zip";
await this.zip(outputSource, outputTarget);
tl.rmRF(outputSource);
if (moveZipToOutputSource) {
fs.mkdirSync(outputSource);
fs.renameSync(outputTarget, path.join(outputSource, path.basename(outputTarget)));
}
// When moveZipToOutputSource is true and zipAfterPublish is true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot this might be expected behavior for some customers, can we make this feature flag based to control the use case

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right. I've implemented this as a feature flag to preserve backwards compatibility. Added a new zipAfterPublishCreateDirectory parameter (defaults to true for legacy behavior) that controls whether the ZIP file is moved into a subdirectory or left at the original location. This way customers can choose the behavior that works best for their use case. Commit: aab9dd2

// we should leave the zip file where it was created and not move it into a subdirectory
// This way the artifact will be the zip file directly instead of a directory containing the zip
}
else {
throw tl.loc("noPublishFolderFoundToZip", projectFile);
Expand Down