Skip to content

Commit 4e91335

Browse files
sanjuyadav24Banner-KeithSanju Yadav
authored
Handle dotnet publish logging the same way as dotnet build. (#21378)
* Handle dotnet publish logging the same way as dotnet build. In Azure DevOps when a publish is run, errors and logs are not picked up properly. This is applying the same fix that was done for the build command. --------- Co-authored-by: Keith Banner <[email protected]> Co-authored-by: Sanju Yadav <[email protected]>
1 parent f86cb5c commit 4e91335

File tree

8 files changed

+177
-85
lines changed

8 files changed

+177
-85
lines changed

Tasks/DotNetCoreCLIV2/Tests/L0.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,17 @@ describe('DotNetCoreExe Suite', function () {
208208
assert(tr.failed, 'task should have failed');
209209
});
210210

211+
it('build passes when zero match found with empty string', async () => {
212+
process.env["__projects__"] = "";
213+
process.env["__command__"] = "build";
214+
let tp = path.join(__dirname, 'validInputs.js')
215+
let tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp);
216+
await tr.runAsync();
217+
218+
assert(tr.invokedToolCount == 1, 'should have invoked tool');
219+
assert(tr.succeeded, 'task should have succeeded');
220+
});
221+
211222
it('test throws warning when zero match found', async () => {
212223
process.env["__projects__"] = "*fail*/project.json";
213224
process.env["__command__"] = "test";
@@ -296,6 +307,20 @@ describe('DotNetCoreExe Suite', function () {
296307
assert(tr.succeeded, 'task should have succeeded');
297308
});
298309

310+
it('publish does not use logger when feature flag is disabled', async () => {
311+
let tp = path.join(__dirname, 'publishWithFeatureFlagDisabled.js');
312+
let tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp);
313+
314+
await tr.runAsync();
315+
316+
assert(tr.invokedToolCount == 1, 'should have invoked tool once');
317+
assert(tr.succeeded, 'task should have succeeded');
318+
assert(tr.ran('dotnet publish web/project.csproj'), 'should have run dotnet publish');
319+
// Verify that the logger argument is NOT present
320+
assert(!tr.stdOutContained('-dl:CentralLogger'), 'should NOT have logger argument when feature flag is disabled');
321+
assert(tr.stdOutContained('published without logger'), 'should have published without logger');
322+
});
323+
299324

300325
it('publish works with publishWebProjects option if .csproj have Microsoft.Net.Sdk.Web', async () => {
301326
process.env["__projects__"] = "validateWebProject.csproj";

Tasks/DotNetCoreCLIV2/Tests/publishInputs.ts

Lines changed: 80 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -11,85 +11,19 @@ tmr.setInput('publishWebProjects', process.env["__publishWebProjects__"] && proc
1111
tmr.setInput('arguments', process.env["__arguments__"] ? process.env["__arguments__"] : "");
1212
tmr.setInput('modifyOutputPath', process.env["modifyOutput"] == "false" ? "false" : "true");
1313

14+
// Get out of the Tests folder to the task root folder. This will match the path used in the task.
15+
// We normalize the string to use forward slashes as that is what the mock answer does and makes this test cross platform.
16+
var loggerAssembly = path.join(__dirname, '..', 'dotnet-build-helpers/Microsoft.TeamFoundation.DistributedTask.MSBuild.Logger.dll').replace(/\\/g, "/");
17+
var loggerString = `-dl:CentralLogger,"${loggerAssembly}"*ForwardingLogger,"${loggerAssembly}"`
18+
1419
let a: ma.TaskLibAnswers = <ma.TaskLibAnswers>{
1520
"which": { "dotnet": "dotnet" },
1621
"checkPath": { "dotnet": true },
1722
"exist": {
1823
"web/web.config": true,
1924
"web2/wwwroot": true,
2025
},
21-
"exec": {
22-
"dotnet publish web/project.json": {
23-
"code": 0,
24-
"stdout": "published",
25-
"stderr": ""
26-
},
27-
"dotnet publish web/project.csproj": {
28-
"code": 0,
29-
"stdout": "published",
30-
"stderr": ""
31-
},
32-
"dotnet publish web2/project.json": {
33-
"code": 0,
34-
"stdout": "published",
35-
"stderr": ""
36-
},
37-
"dotnet publish web.tests/project.json": {
38-
"code": 0,
39-
"stdout": "published",
40-
"stderr": ""
41-
},
42-
"dotnet publish lib/project.json": {
43-
"code": 0,
44-
"stdout": "published",
45-
"stderr": ""
46-
},
47-
"dotnet publish web3/project.json --configuration release --output /usr/out/web3": {
48-
"code": 0,
49-
"stdout": "published",
50-
"stderr": ""
51-
},
52-
"dotnet publish lib2/project.json --configuration release --output /usr/out/lib2": {
53-
"code": 0,
54-
"stdout": "published",
55-
"stderr": ""
56-
},
57-
"dotnet publish web3/project.json --configuration release --output /usr/out": {
58-
"code": 0,
59-
"stdout": "published web3 without adding project name to path\n",
60-
"stderr": ""
61-
},
62-
"dotnet publish lib2/project.json --configuration release --output /usr/out": {
63-
"code": 0,
64-
"stdout": "published lib2 without adding project name to path\n",
65-
"stderr": ""
66-
},
67-
"dotnet publish --configuration release --output /usr/out": {
68-
"code": 0,
69-
"stdout": "published without adding project name to path\n",
70-
"stderr": ""
71-
},
72-
"dotnet publish": {
73-
"code": 0,
74-
"stdout": "published",
75-
"stderr": ""
76-
},
77-
"dotnet publish web/project.csproj --configuration release --output /usr/out/web": {
78-
"code": 0,
79-
"stdout": "published",
80-
"stderr": ""
81-
},
82-
"dotnet publish lib/project.csproj --configuration release --output /usr/out": {
83-
"code": 0,
84-
"stdout": "published",
85-
"stderr": ""
86-
},
87-
"dotnet publish dummy/project.json": {
88-
"code": 1,
89-
"stdout": "not published",
90-
"stderr": ""
91-
}
92-
},
26+
"exec": {},
9327
"findMatch": {
9428
"**/project.json": ["web/project.json", "web2/project.json", "web.tests/project.json", "lib/project.json"],
9529
"**/project.json;**/*.csproj": ["web/project.json", "web2/project.json", "web.tests/project.json", "lib/project.json"],
@@ -98,10 +32,83 @@ let a: ma.TaskLibAnswers = <ma.TaskLibAnswers>{
9832
"*fail*/project.json": [],
9933
"*customoutput/project.json": ["web3/project.json", "lib2/project.json"],
10034
"dummy/project.json": ["dummy/project.json"],
101-
"" : []
35+
"": []
10236
}
10337
};
10438

39+
// Refactored exec values using bracket notation to allow dynamic keys
40+
// This accounts for different paths on different developer machines
41+
a["exec"][`dotnet publish web/project.json ${loggerString}`] = {
42+
"code": 0,
43+
"stdout": "published",
44+
"stderr": ""
45+
};
46+
a["exec"][`dotnet publish web/project.csproj ${loggerString}`] = {
47+
"code": 0,
48+
"stdout": "published",
49+
"stderr": ""
50+
};
51+
a["exec"][`dotnet publish web2/project.json ${loggerString}`] = {
52+
"code": 0,
53+
"stdout": "published",
54+
"stderr": ""
55+
};
56+
a["exec"][`dotnet publish web.tests/project.json ${loggerString}`] = {
57+
"code": 0,
58+
"stdout": "published",
59+
"stderr": ""
60+
};
61+
a["exec"][`dotnet publish lib/project.json ${loggerString}`] = {
62+
"code": 0,
63+
"stdout": "published",
64+
"stderr": ""
65+
};
66+
a["exec"][`dotnet publish web3/project.json ${loggerString} --configuration release --output /usr/out/web3`] = {
67+
"code": 0,
68+
"stdout": "published",
69+
"stderr": ""
70+
};
71+
a["exec"][`dotnet publish lib2/project.json ${loggerString} --configuration release --output /usr/out/lib2`] = {
72+
"code": 0,
73+
"stdout": "published",
74+
"stderr": ""
75+
};
76+
a["exec"][`dotnet publish web3/project.json ${loggerString} --configuration release --output /usr/out`] = {
77+
"code": 0,
78+
"stdout": "published web3 without adding project name to path\n",
79+
"stderr": ""
80+
};
81+
a["exec"][`dotnet publish lib2/project.json ${loggerString} --configuration release --output /usr/out`] = {
82+
"code": 0,
83+
"stdout": "published lib2 without adding project name to path\n",
84+
"stderr": ""
85+
};
86+
a["exec"][`dotnet publish ${loggerString} --configuration release --output /usr/out`] = {
87+
"code": 0,
88+
"stdout": "published without adding project name to path\n",
89+
"stderr": ""
90+
};
91+
a["exec"][`dotnet publish ${loggerString}`] = {
92+
"code": 0,
93+
"stdout": "published",
94+
"stderr": ""
95+
};
96+
a["exec"][`dotnet publish web/project.csproj ${loggerString} --configuration release --output /usr/out/web`] = {
97+
"code": 0,
98+
"stdout": "published",
99+
"stderr": ""
100+
};
101+
a["exec"][`dotnet publish lib/project.csproj ${loggerString} --configuration release --output /usr/out`] = {
102+
"code": 0,
103+
"stdout": "published",
104+
"stderr": ""
105+
};
106+
a["exec"][`dotnet publish dummy/project.json ${loggerString}`] = {
107+
"code": 1,
108+
"stdout": "not published",
109+
"stderr": ""
110+
};
111+
105112
process.env["MOCK_NORMALIZE_SLASHES"] = "true";
106113
tmr.setAnswers(a);
107114
tmr.registerMock('azure-pipelines-task-lib/toolrunner', require('azure-pipelines-task-lib/mock-toolrunner'));
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
5+
let taskPath = path.join(__dirname, '..', 'dotnetcore.js');
6+
let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);
7+
8+
// Set the feature flag to disable the publish logger
9+
process.env["DISTRIBUTEDTASK_TASKS_DISABLEDOTNETPUBLISHLOGGER"] = "true";
10+
11+
tmr.setInput('command', "publish");
12+
tmr.setInput('projects', "web/project.csproj");
13+
tmr.setInput('publishWebProjects', "false");
14+
tmr.setInput('arguments', "");
15+
16+
let a: ma.TaskLibAnswers = <ma.TaskLibAnswers>{
17+
"which": { "dotnet": "dotnet" },
18+
"checkPath": { "dotnet": true },
19+
"exec": {},
20+
"findMatch": {
21+
"web/project.csproj": ["web/project.csproj"]
22+
}
23+
};
24+
25+
// When feature flag is enabled (disables logger), expect publish WITHOUT logger argument
26+
a["exec"]["dotnet publish web/project.csproj"] = {
27+
"code": 0,
28+
"stdout": "published without logger",
29+
"stderr": ""
30+
};
31+
32+
tmr.setAnswers(a);
33+
tmr.run();

Tasks/DotNetCoreCLIV2/Tests/validInputs.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ let nmh: util.DotnetMockHelper = new util.DotnetMockHelper(tmr);
1010
tmr.setInput('command', process.env["__command__"]);
1111
tmr.setInput('projects', process.env["__projects__"]);
1212

13+
// Get out of the Tests folder to the task root folder. This will match the path used in the task.
14+
// We normalize the string to use forward slashes as that is what the mock answer does and makes this test cross platform.
15+
var loggerAssembly = path.join(__dirname, '..', 'dotnet-build-helpers/Microsoft.TeamFoundation.DistributedTask.MSBuild.Logger.dll').replace(/\\/g, "/");
16+
var loggerString = `-dl:CentralLogger,"${loggerAssembly}"*ForwardingLogger,"${loggerAssembly}"`
17+
1318
let a: ma.TaskLibAnswers = <ma.TaskLibAnswers>{
1419
"which": { "dotnet": "dotnet" },
1520
"checkPath": { "dotnet": true },
@@ -43,12 +48,7 @@ let a: ma.TaskLibAnswers = <ma.TaskLibAnswers>{
4348
"code": 1,
4449
"stdout": "not restored",
4550
"stderr": ""
46-
},
47-
"dotnet build": {
48-
"code": 0,
49-
"stdout": "built",
50-
"stderr": ""
51-
},
51+
}
5252
},
5353
"findMatch": {
5454
"**/project.json": ["web/project.json", "web2/project.json", "web.tests/project.json", "lib/project.json"],
@@ -60,6 +60,14 @@ let a: ma.TaskLibAnswers = <ma.TaskLibAnswers>{
6060
"" : []
6161
}
6262
};
63+
64+
a["exec"][`dotnet build ${loggerString}`] = {
65+
"code": 0,
66+
"stdout": "built",
67+
"stderr": ""
68+
};
69+
70+
process.env["MOCK_NORMALIZE_SLASHES"] = "true";
6371
tmr.setAnswers(a);
6472
tmr.registerMock('azure-pipelines-task-lib/toolrunner', require('azure-pipelines-task-lib/mock-toolrunner'));
6573

Tasks/DotNetCoreCLIV2/Tests/validateWebProject.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ tmr.setInput('workingDirectory', process.env["workingDirectory"] ? process.env["
1616
process.env['TASK_TEST_TRACE'] = "true";
1717

1818
var projectFile = path.join(__dirname, process.env["__projects__"]);
19-
var execCommand = "dotnet publish " + projectFile
19+
20+
// Get out of the Tests folder to the task root folder. This will match the path used in the task.
21+
var loggerAssembly = path.join(__dirname, '..', 'dotnet-build-helpers/Microsoft.TeamFoundation.DistributedTask.MSBuild.Logger.dll');
22+
var loggerString = `-dl:CentralLogger,"${loggerAssembly}"*ForwardingLogger,"${loggerAssembly}"`
23+
24+
var execCommand = `dotnet publish ${projectFile} ${loggerString}`;
2025

2126
let a: ma.TaskLibAnswers = <ma.TaskLibAnswers>{
2227
"which": {

Tasks/DotNetCoreCLIV2/dotnetcore.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export class dotNetExe {
118118
} else {
119119
dotnet.arg(projectFile);
120120
}
121-
if (this.isBuildCommand()) {
121+
if (this.isBuildCommand() || (this.isPublishCommand() && this.shouldUsePublishLogger())) {
122122
var loggerAssembly = path.join(__dirname, 'dotnet-build-helpers/Microsoft.TeamFoundation.DistributedTask.MSBuild.Logger.dll');
123123
dotnet.arg(`-dl:CentralLogger,\"${loggerAssembly}\"*ForwardingLogger,\"${loggerAssembly}\"`);
124124
}
@@ -463,6 +463,20 @@ export class dotNetExe {
463463
return this.command === "run";
464464
}
465465

466+
private shouldUsePublishLogger(): boolean {
467+
// Feature flag to control MSBuild logger for dotnet publish command
468+
// Default: enabled (opt-out pattern) - users can disable if needed
469+
// Set DISTRIBUTEDTASK_TASKS_DISABLEDOTNETPUBLISHLOGGER=true to disable
470+
const disablePublishLogger = tl.getPipelineFeature('DisableDotNetPublishLogger');
471+
472+
if (disablePublishLogger) {
473+
tl.debug('MSBuild logger disabled for dotnet publish via feature flag DisableDotNetPublishLogger');
474+
return false;
475+
}
476+
477+
return true;
478+
}
479+
466480
private static getModifiedOutputForProjectFile(outputBase: string, projectFile: string): string {
467481
return path.join(outputBase, path.basename(path.dirname(projectFile)));
468482
}

Tasks/DotNetCoreCLIV2/task.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
"demands": [],
1818
"version": {
1919
"Major": 2,
20-
"Minor": 263,
21-
"Patch": 0
20+
"Minor": 264,
21+
"Patch": 1
2222
},
2323
"minimumAgentVersion": "2.144.0",
2424
"instanceNameFormat": "dotnet $(command)",

Tasks/DotNetCoreCLIV2/task.loc.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
"demands": [],
1818
"version": {
1919
"Major": 2,
20-
"Minor": 263,
21-
"Patch": 0
20+
"Minor": 264,
21+
"Patch": 1
2222
},
2323
"minimumAgentVersion": "2.144.0",
2424
"instanceNameFormat": "ms-resource:loc.instanceNameFormat",

0 commit comments

Comments
 (0)