diff --git a/Tasks/DotNetCoreCLIV2/Strings/resources.resjson/en-US/resources.resjson b/Tasks/DotNetCoreCLIV2/Strings/resources.resjson/en-US/resources.resjson
index d0d9d231d4d6..5686558c03d5 100644
--- a/Tasks/DotNetCoreCLIV2/Strings/resources.resjson/en-US/resources.resjson
+++ b/Tasks/DotNetCoreCLIV2/Strings/resources.resjson/en-US/resources.resjson
@@ -103,7 +103,7 @@
"loc.messages.dotnetCommandFailed": "Dotnet command failed with non-zero exit code on the following projects : %s",
"loc.messages.noProjectFilesFound": "Project file(s) matching the specified pattern were not found.",
"loc.messages.noPublishFolderFoundToZip": "A publish folder could not be found to zip for project file: %s.",
- "loc.messages.noWebProjctFound": "No web project was found in the repository. Web projects are identified by presence of either a web.config file or wwwroot folder in the directory.",
+ "loc.messages.noWebProjectFound": "No web project was found in the repository. Web projects are identified by presence of either a web.config file, wwwroot folder in the directory, or by the usage of Microsoft.Net.Web.Sdk in your project file. You can set Publish Web Projects property to false (publishWebProjects: false in yml) if your project doesn't follow this convention or if you want to publish projects other than web projects.",
"loc.messages.zipFailed": "Zip failed with error: %s",
"loc.messages.Error_ApiKeyNotSupported": "DotNetCore currently does not support using an encrypted Api Key.",
"loc.messages.Error_ExpectedConfigurationElement": "Invalid xml. Expected element named 'configuration'.",
diff --git a/Tasks/DotNetCoreCLIV2/Tests/L0.ts b/Tasks/DotNetCoreCLIV2/Tests/L0.ts
index adc86a690a3d..2bef4b77d2b0 100644
--- a/Tasks/DotNetCoreCLIV2/Tests/L0.ts
+++ b/Tasks/DotNetCoreCLIV2/Tests/L0.ts
@@ -312,6 +312,20 @@ describe('DotNetCoreExe Suite', function () {
done();
});
+
+ it('publish works with publishWebProjects option if .csproj have Microsoft.Net.Sdk.Web', (done: MochaDone) => {
+ process.env["__projects__"] = "validateWebProject.csproj";
+ process.env["workingDirectory"] = ".";
+ process.env["__publishWebProject__"] = "true";
+ let tp = path.join(__dirname, 'validateWebProject.js');
+ let tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp);
+ tr.run();
+
+ assert(tr.invokedToolCount == 1, 'should have invoked been invoked once');
+ assert(tr.succeeded, 'task should have succeeded');
+ done();
+ })
+
it('publish updates the output with the project name appended', (done: MochaDone) => {
process.env["__projects__"] = "*customoutput/project.json";
process.env["__publishWebProjects__"] = "false";
diff --git a/Tasks/DotNetCoreCLIV2/Tests/validateWebProject.csproj b/Tasks/DotNetCoreCLIV2/Tests/validateWebProject.csproj
new file mode 100644
index 000000000000..8fc9f6a49bc2
--- /dev/null
+++ b/Tasks/DotNetCoreCLIV2/Tests/validateWebProject.csproj
@@ -0,0 +1,17 @@
+
+
+
+ netcoreapp2.1
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tasks/DotNetCoreCLIV2/Tests/validateWebProject.ts b/Tasks/DotNetCoreCLIV2/Tests/validateWebProject.ts
new file mode 100644
index 000000000000..0c9044dc1f00
--- /dev/null
+++ b/Tasks/DotNetCoreCLIV2/Tests/validateWebProject.ts
@@ -0,0 +1,42 @@
+import ma = require('azure-pipelines-task-lib/mock-answer');
+import tmrm = require('azure-pipelines-task-lib/mock-run');
+import path = require('path');
+
+let taskPath = path.join(__dirname, '..', 'dotnetcore.js');
+let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);
+
+tmr.setInput('command', "publish");
+tmr.setInput('projects', process.env["__projects__"]);
+tmr.setInput('publishWebProjects', process.env["__publishWebProjects__"] && process.env["__publishWebProjects__"] == "true" ? "true" : "false");
+tmr.setInput('arguments', process.env["__arguments__"] ? process.env["__arguments__"] : "");
+tmr.setInput('modifyOutputPath', process.env["modifyOutput"] == "false" ? "false" : "true");
+tmr.setInput('zipAfterPublish', process.env["zipAfterPublish"] ? process.env["zipAfterPublish"] : "false");
+tmr.setInput('workingDirectory', process.env["workingDirectory"] ? process.env["workingDirectory"] : "");
+
+process.env['TASK_TEST_TRACE'] = "true";
+
+var projectFile = path.join(__dirname, process.env["__projects__"]);
+var execCommand = "dotnet publish " + projectFile
+
+let a: ma.TaskLibAnswers = {
+ "which": {
+ "dotnet": "dotnet",
+ },
+ "checkPath": { "dotnet": true },
+ "exec": {},
+ "findMatch": {
+ "**/*.csproj\n**/*.vbproj\n**/*.fsproj": [projectFile]
+ }
+}
+
+a['exec'][execCommand] = {
+ "code": 0,
+ "stdout": "published",
+ "stderr": ""
+}
+
+process.env["MOCK_NORMALIZE_SLASHES"] = "true";
+tmr.setAnswers(a)
+tmr.registerMock('azure-pipelines-task-lib/toolrunner', require('azure-pipelines-task-lib/mock-toolrunner'));
+
+tmr.run();
\ No newline at end of file
diff --git a/Tasks/DotNetCoreCLIV2/dotnetcore.ts b/Tasks/DotNetCoreCLIV2/dotnetcore.ts
index d30c33978713..ce3ab486bfd4 100644
--- a/Tasks/DotNetCoreCLIV2/dotnetcore.ts
+++ b/Tasks/DotNetCoreCLIV2/dotnetcore.ts
@@ -2,6 +2,7 @@ import tl = require("azure-pipelines-task-lib/task");
import tr = require("azure-pipelines-task-lib/toolrunner");
import path = require("path");
import fs = require("fs");
+import ltx = require("ltx");
var archiver = require('archiver');
import * as packCommand from './packcommand';
@@ -325,22 +326,50 @@ export class dotNetExe {
}
var projectFiles = utility.getProjectFiles(projectPattern);
+ var resolvedProjectFiles: string[] = [];
if (searchWebProjects) {
- projectFiles = projectFiles.filter(function (file, index, files): boolean {
+ resolvedProjectFiles = projectFiles.filter(function (file, index, files): boolean {
var directory = path.dirname(file);
return tl.exist(path.join(directory, "web.config"))
|| tl.exist(path.join(directory, "wwwroot"));
});
- if (!projectFiles.length) {
- tl.error(tl.loc("noWebProjctFound"));
- }
+ if (!resolvedProjectFiles.length) {
+ var projectFilesUsingWebSdk = projectFiles.filter(this.isWebSdkUsed);
+ if(!projectFilesUsingWebSdk.length) {
+ tl.error(tl.loc("noWebProjectFound"));
+ }
+ return projectFilesUsingWebSdk;
+ }
+ return resolvedProjectFiles;
}
-
return projectFiles;
}
+ private isWebSdkUsed(projectfile: string): boolean {
+ if (projectfile.endsWith('.vbproj')) return false
+
+ try {
+ var fileBuffer: Buffer = fs.readFileSync(projectfile);
+ var webConfigContent: string;
+
+ var fileEncodings = ['utf8', 'utf16le'];
+
+ for(var i = 0; i < fileEncodings.length; i++) {
+ tl.debug("Trying to decode with " + fileEncodings[i]);
+ webConfigContent = fileBuffer.toString(fileEncodings[i]);
+ try {
+ var projectSdkUsed: string = ltx.parse(webConfigContent).getAttr("sdk") || ltx.parse(webConfigContent).getAttr("Sdk");
+ return projectSdkUsed && projectSdkUsed.toLowerCase() == "microsoft.net.sdk.web";
+ } catch (error) {}
+ }
+ } catch(error) {
+ tl.warning(error);
+ }
+ return false;
+ }
+
private isPublishCommand(): boolean {
return this.command === "publish";
}
diff --git a/Tasks/DotNetCoreCLIV2/package-lock.json b/Tasks/DotNetCoreCLIV2/package-lock.json
index 7c8244da0df6..4cd4affe6b77 100644
--- a/Tasks/DotNetCoreCLIV2/package-lock.json
+++ b/Tasks/DotNetCoreCLIV2/package-lock.json
@@ -107,20 +107,19 @@
}
},
"azure-devops-node-api": {
- "version": "6.6.3",
- "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-6.6.3.tgz",
- "integrity": "sha512-94wSu4O6CSSXoqYWg7Rzt2/IqbW2xVNu2qOtx6e7lnXxnDOcAu4eRzi8tgVNHsXTIGOVEsTqgMvGvFThKr9Pig==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-8.0.0.tgz",
+ "integrity": "sha512-QkIzphuE3y/hZVMB6ONN0Dev5r9+CIAiopWulwoYx1Er0kYcsbXsKXKynuLSxsVPocMppbr4YPhTsX2eHY/Mjw==",
"requires": {
- "os": "0.1.1",
"tunnel": "0.0.4",
- "typed-rest-client": "1.0.9",
+ "typed-rest-client": "1.2.0",
"underscore": "1.8.3"
},
"dependencies": {
"typed-rest-client": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.0.9.tgz",
- "integrity": "sha512-iOdwgmnP/tF6Qs+oY4iEtCf/3fnCDl7Gy9LGPJ4E3M4Wj3uaSko15FVwbsaBmnBqTJORnXBWVY5306D4HH8oiA==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.2.0.tgz",
+ "integrity": "sha512-FrUshzZ1yxH8YwGR29PWWnfksLEILbWJydU7zfIRkyH7kAEzB62uMAl2WY6EyolWpLpVHeJGgQm45/MaruaHpw==",
"requires": {
"tunnel": "0.0.4",
"underscore": "1.8.3"
@@ -313,17 +312,20 @@
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
},
"ip-address": {
- "version": "5.9.0",
- "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-5.9.0.tgz",
- "integrity": "sha512-+4yKpEyent8IpjuDQVkIpzIDbxSlCHTPdmaXCRLH0ttt3YsrbNxuZJ6h+1wLPx10T7gWsLN7M6BXIHV2vZNOGw==",
+ "version": "5.9.2",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-5.9.2.tgz",
+ "integrity": "sha512-7aeFm/7oqo0mMhubTSjZ2Juw/F+WJ3hyfCScNVRQdz5RSRhw1Rj4ZlBFsmEajeKgQDI8asqVs31h8DpxEv7IfQ==",
"requires": {
"jsbn": "1.1.0",
- "lodash.find": "^4.6.0",
- "lodash.max": "^4.0.1",
- "lodash.merge": "^4.6.1",
- "lodash.padstart": "^4.6.1",
- "lodash.repeat": "^4.1.0",
- "sprintf-js": "1.1.1"
+ "lodash": "^4.17.11",
+ "sprintf-js": "1.1.2"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "4.17.11",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+ "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
+ }
}
},
"isarray": {
@@ -358,31 +360,6 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
},
- "lodash.find": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz",
- "integrity": "sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E="
- },
- "lodash.max": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/lodash.max/-/lodash.max-4.0.1.tgz",
- "integrity": "sha1-hzVWbGGLNan3YFILSHrnllivE2o="
- },
- "lodash.merge": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz",
- "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ=="
- },
- "lodash.padstart": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz",
- "integrity": "sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs="
- },
- "lodash.repeat": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/lodash.repeat/-/lodash.repeat-4.1.0.tgz",
- "integrity": "sha1-/H3oEx2MisB+S0n3T/6CnR8r7EQ="
- },
"ltx": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/ltx/-/ltx-2.8.1.tgz",
@@ -420,11 +397,6 @@
"wrappy": "1"
}
},
- "os": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/os/-/os-0.1.1.tgz",
- "integrity": "sha1-IIhF6J4ZOtTZcUdLk5R3NqVtE/M="
- },
"packaging-common": {
"version": "file:../../_build/Tasks/Common/packaging-common-1.0.1.tgz",
"requires": {
@@ -435,14 +407,14 @@
"@types/node": "10.12.9",
"@types/q": "1.5.2",
"adm-zip": "^0.4.11",
- "azure-devops-node-api": "^6.6.0",
+ "azure-devops-node-api": "8.0.0",
"azure-pipelines-task-lib": "2.8.0",
"azure-pipelines-tool-lib": "0.12.0",
"ini": "^1.3.4",
"ip-address": "^5.8.9",
"ltx": "^2.6.2",
"q": "^1.5.0",
- "typed-rest-client": "0.12.0"
+ "typed-rest-client": "1.2.0"
}
},
"path-is-absolute": {
@@ -500,9 +472,9 @@
"integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E="
},
"sprintf-js": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz",
- "integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw="
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
+ "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
},
"string_decoder": {
"version": "1.0.3",
@@ -529,9 +501,9 @@
"integrity": "sha1-LTeFoVjBdMmhbcLARuxfxfF0IhM="
},
"typed-rest-client": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-0.12.0.tgz",
- "integrity": "sha1-Y3b1Un9CfaEh3K/f1+QeEyHgcgw=",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.2.0.tgz",
+ "integrity": "sha512-FrUshzZ1yxH8YwGR29PWWnfksLEILbWJydU7zfIRkyH7kAEzB62uMAl2WY6EyolWpLpVHeJGgQm45/MaruaHpw==",
"requires": {
"tunnel": "0.0.4",
"underscore": "1.8.3"
@@ -561,16 +533,6 @@
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
- },
- "vso-node-api": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/vso-node-api/-/vso-node-api-6.5.0.tgz",
- "integrity": "sha512-hFjPLMJkq02zF8U+LhZ4airH0ivaiKzGdlNAQlYFB3lWuGH/UANUrl63DVPUQOyGw+7ZNQ+ufM44T6mWN92xyg==",
- "requires": {
- "tunnel": "0.0.4",
- "typed-rest-client": "^0.12.0",
- "underscore": "1.8.3"
- }
}
}
},
@@ -580,13 +542,24 @@
"integrity": "sha1-PdPT55Crwk17DToDT/q6vijrvAQ="
},
"vso-node-api": {
- "version": "6.0.1-preview",
- "resolved": "https://registry.npmjs.org/vso-node-api/-/vso-node-api-6.0.1-preview.tgz",
- "integrity": "sha1-RBprv5s8aNpiTbAeo1y6jwpMLKs=",
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/vso-node-api/-/vso-node-api-6.5.0.tgz",
+ "integrity": "sha512-hFjPLMJkq02zF8U+LhZ4airH0ivaiKzGdlNAQlYFB3lWuGH/UANUrl63DVPUQOyGw+7ZNQ+ufM44T6mWN92xyg==",
"requires": {
- "q": "^1.0.1",
"tunnel": "0.0.4",
- "underscore": "^1.8.3"
+ "typed-rest-client": "^0.12.0",
+ "underscore": "1.8.3"
+ },
+ "dependencies": {
+ "typed-rest-client": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-0.12.0.tgz",
+ "integrity": "sha1-Y3b1Un9CfaEh3K/f1+QeEyHgcgw=",
+ "requires": {
+ "tunnel": "0.0.4",
+ "underscore": "1.8.3"
+ }
+ }
}
},
"vsts-task-lib": {
diff --git a/Tasks/DotNetCoreCLIV2/task.json b/Tasks/DotNetCoreCLIV2/task.json
index 070a9bd4c396..58c1b8b8937f 100644
--- a/Tasks/DotNetCoreCLIV2/task.json
+++ b/Tasks/DotNetCoreCLIV2/task.json
@@ -18,7 +18,7 @@
"version": {
"Major": 2,
"Minor": 153,
- "Patch": 2
+ "Patch": 3
},
"minimumAgentVersion": "2.115.0",
"instanceNameFormat": "dotnet $(command)",
@@ -529,7 +529,7 @@
"dotnetCommandFailed": "Dotnet command failed with non-zero exit code on the following projects : %s",
"noProjectFilesFound": "Project file(s) matching the specified pattern were not found.",
"noPublishFolderFoundToZip": "A publish folder could not be found to zip for project file: %s.",
- "noWebProjctFound": "No web project was found in the repository. Web projects are identified by presence of either a web.config file or wwwroot folder in the directory.",
+ "noWebProjectFound": "No web project was found in the repository. Web projects are identified by presence of either a web.config file, wwwroot folder in the directory, or by the usage of Microsoft.Net.Web.Sdk in your project file. You can set Publish Web Projects property to false (publishWebProjects: false in yml) if your project doesn't follow this convention or if you want to publish projects other than web projects.",
"zipFailed": "Zip failed with error: %s",
"Error_ApiKeyNotSupported": "DotNetCore currently does not support using an encrypted Api Key.",
"Error_ExpectedConfigurationElement": "Invalid xml. Expected element named 'configuration'.",
diff --git a/Tasks/DotNetCoreCLIV2/task.loc.json b/Tasks/DotNetCoreCLIV2/task.loc.json
index ee46e8d26476..a33e671ae7ba 100644
--- a/Tasks/DotNetCoreCLIV2/task.loc.json
+++ b/Tasks/DotNetCoreCLIV2/task.loc.json
@@ -18,7 +18,7 @@
"version": {
"Major": 2,
"Minor": 153,
- "Patch": 2
+ "Patch": 3
},
"minimumAgentVersion": "2.115.0",
"instanceNameFormat": "ms-resource:loc.instanceNameFormat",