Skip to content

Commit

Permalink
Publish Visual Studio Extension task (#109)
Browse files Browse the repository at this point in the history
* change VSTS Marketplace to VS Marketplace
* Publish VS Extension task
* change VSTS Marketplace to VS Marketplace
* One less uncaught promise rejection Fixes #108
* fix review comments
  • Loading branch information
onlyutkarsh authored and jessehouwing committed Jan 29, 2019
1 parent 563b4fc commit dc8b30a
Show file tree
Hide file tree
Showing 14 changed files with 647 additions and 188 deletions.
45 changes: 45 additions & 0 deletions BuildTasks/PublishVSExtension/PublishVSExtension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as tl from "azure-pipelines-task-lib";
import tr = require("azure-pipelines-task-lib/toolrunner");
import * as util from "./Utils";

let publisher = "";

try {
let connectedService = tl.getInput("ConnectedServiceName", true);
let token = tl.getEndpointAuthorizationParameter(connectedService, "password", true);

let vsixFile = tl.getPathInput("vsixFile", true, false);
let rootFolder = tl.getPathInput("rootFolder", false) || tl.getVariable("System.DefaultWorkingDirectory");
let manifestPattern = tl.getPathInput("manifestPattern", false, false) || "extension.manifest.json";
let publisherId = tl.getInput("publisherId", true);
publisher = publisherId;
let internalName = tl.getInput("internalName", false);
let extensionVisibility = tl.getInput("extensionVisibility", false);
let extensionPricing = tl.getInput("extensionPricing", false);
let ignoreWarnings = tl.getInput("ignoreWarnings", false);

console.info(`Logging in as '${publisherId}'`);
util.login(publisherId, token);

console.info(`Searching for manifest file '${manifestPattern}' in '${rootFolder}'`);
let manifestPathList = tl.findMatch(rootFolder, manifestPattern);
if (manifestPathList && manifestPathList.length === 0) {
throw new Error("Could not find manifest file.");
}
let manifestPath = manifestPathList[0];

console.info(`Found manifest file: ${manifestPath} `)

console.info(`Publishing '${vsixFile}' to Visual Studio marketplace`)
util.publish(vsixFile, manifestPath, ignoreWarnings);

} catch (error) {
tl.error(error);
tl.setResult(tl.TaskResult.Failed, error);
}
finally {
console.info(`Logging out publisher '${publisher}'`);
util.logout(publisher);
console.log("All done");
}

85 changes: 85 additions & 0 deletions BuildTasks/PublishVSExtension/Utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import * as tl from "azure-pipelines-task-lib";
import tr = require("azure-pipelines-task-lib/toolrunner");
import * as path from "path";

let cacheVsixPublisherExe = "";

export function getVsixPublisherExe(): string {
if (cacheVsixPublisherExe == "") {
const vswhereTool = tl.tool(path.join(__dirname, "tools", "vswhere.exe"));
vswhereTool.line("-version [15.0,16.0) -latest -requires Microsoft.VisualStudio.Component.VSSDK -property installationPath");
let vsPath = vswhereTool.execSync({ silent: true } as tr.IExecSyncOptions).stdout;
vsPath = vsPath.trim();
tl.debug('Visual Studio 15.0 or higher installed path: ' + vsPath);
if (!isNullOrWhitespace(vsPath)) {
let vsixPublisherFolder = path.join(vsPath, 'VSSDK', 'VisualStudioIntegration', 'Tools', 'Bin');
if (!vsixPublisherFolder) {
let message = "Unable to find instance of Visual Studio with VSSDK installed...";
throw new Error(message);

}
tl.debug(`VSINSTALLDIR: '${vsixPublisherFolder}'`);
let vsixPublisherExe = path.join(vsixPublisherFolder, "VsixPublisher.exe");
let vsixPublisherExists = tl.which(vsixPublisherExe, true);
if (!vsixPublisherExists) {
let message = `Could not find VSIXPublisher.exe under '${vsixPublisherFolder}'`;
throw new Error(message);
}

tl.debug(`VSIXPublisher.exe path: '${vsixPublisherExe}'`);

cacheVsixPublisherExe = vsixPublisherExe;
return vsixPublisherExe;
}
}
else {
return cacheVsixPublisherExe;
}
return null;
}

export function isNullOrWhitespace(input) {
if (typeof input === 'undefined' || input === null) {
return true;
}
return input.replace(/\s/g, '').length < 1;
}

export function login(publisher: string, token: string) {
let vsixPublisherExe = getVsixPublisherExe();
let vsixPublisher = tl.tool(vsixPublisherExe);

vsixPublisher.arg("login");
vsixPublisher.arg(["-personalAccessToken", token]);
vsixPublisher.arg(["-publisherName", publisher]);

vsixPublisher.execSync({ failOnStdErr: true } as tr.IExecOptions);

console.info(`Login successful.`)
}
export function logout(publisher: string) {
let vsixPublisherExe = getVsixPublisherExe();
let vsixPublisher = tl.tool(vsixPublisherExe);

vsixPublisher.arg("logout");
vsixPublisher.arg(["-publisherName", publisher]);
vsixPublisher.arg("-ignoreMissingPublisher");

vsixPublisher.execSync({ failOnStdErr: true } as tr.IExecOptions);

console.info(`Logout successful.`)
}

export function publish(vsixPath: string, manifestPath: string, warningsToIgnore: string) {
let vsixPublisherExe = getVsixPublisherExe();
let vsixPublisher = tl.tool(vsixPublisherExe);

vsixPublisher.arg("publish");
vsixPublisher.arg(["-payload", vsixPath]);
vsixPublisher.arg(["-publishManifest", manifestPath]);
vsixPublisher.arg(["-ignoreWarnings", warningsToIgnore]);

vsixPublisher.execSync({ failOnStdErr: true } as tr.IExecOptions);

console.info(`Published successfully.`)
}
Binary file added BuildTasks/PublishVSExtension/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
117 changes: 117 additions & 0 deletions BuildTasks/PublishVSExtension/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions BuildTasks/PublishVSExtension/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "publishvsextension",
"version": "1.0.0",
"description": "Publish Visual Studio Extension Task",
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/vsts-extension-build-release-tasks.git"
},
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"license": "MIT",
"dependencies": {
"azure-pipelines-task-lib": "^2.7.7",
"core-js": "^2.6.3",
"path": "~0.12.7"
},
"devDependencies": {
"@types/node": "10.12.19",
"@types/q": "~1.5.1"
}
}
12 changes: 12 additions & 0 deletions BuildTasks/PublishVSExtension/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## Publish Visual Studio Extension task

With this task you will be able to publish a Visual Studio extension to Marketplace.

This task uses [VSIXPublisher](https://docs.microsoft.com/en-us/visualstudio/extensibility/walkthrough-publishing-a-visual-studio-extension-via-command-line?view=vs-2017) program to publish Visual Studio extension to Marketplace.

> VSIXPublisher executable is not shipped with this task, hence this task needs to be run on an agent where at least Visual Studio 2017 with `Microsoft.VisualStudio.Component.VSSDK` workload installed. `Hosted VS 2017` pool contains agents with both Visual Studio and Microsoft.VisualStudio.Component.VSSDK installed.
### Screenshot

![screenshot](screenshot.png)

Binary file added BuildTasks/PublishVSExtension/screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
90 changes: 90 additions & 0 deletions BuildTasks/PublishVSExtension/task.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"id": "17654839-813a-4e5f-a724-223a68ec647c",
"name": "PublishVSExtension",
"friendlyName": "Publish Visual Studio Extension",
"description": "Publish Visual Studio extension to the Visual Studio Marketplace",
"author": "Microsoft Corporation",
"helpMarkDown": "[More Information](https://marketplace.visualstudio.com/items?itemName=ms-devlabs.vsts-developer-tools-build-tasks)",
"preview": true,
"category": "Deploy",
"version": {
"Major": 1,
"Minor": 0,
"Patch": 0
},
"visibility": [
"Build",
"Release"
],
"demands": [
"visualstudio"
],
"minimumAgentVersion": "1.83.0",
"groups": [],
"instanceNameFormat": "Publish Visual Studio Extension",
"inputs": [
{
"name": "connectedServiceName",
"type": "connectedService:VstsMarketplacePublishing",
"label": "Visual Studio Marketplace connection",
"required": true,
"helpMarkDown": "Service endpoint connection to install the extension."
},
{
"name": "vsixFile",
"type": "filePath",
"label": "VSIX file",
"defaultValue": "",
"required": true,
"helpMarkDown": "VSIX file to publish."
},
{
"name": "rootFolder",
"type": "filePath",
"label": "Root manifest folder",
"defaultValue": "",
"required": false,
"helpMarkDown": "Folder where manifest file(s) exist."
},
{
"name": "manifestPattern",
"type": "string",
"label": "Manifest file",
"defaultValue": "extension-manifest.json",
"required": false,
"helpMarkDown": "Pattern for the manifest file. If multiple manifest files are found, first one will be picked up."
},
{
"name": "publisherId",
"type": "string",
"label": "Publisher ID",
"defaultValue": "",
"required": true,
"helpMarkDown": "Extension publisher ID."
},
{
"name": "ignoreWarnings",
"type": "string",
"label": "Warnings to ignore",
"defaultValue": "",
"helpMarkDown": "List of warnings to ignore when publishing an extension. These warnings are shown as command line messages when publishing an extension. (for example, \"VSIXValidatorWarning01, VSIXValidatorWarning02\")",
"required": false
}
],
"execution": {
"Node10": {
"target": "PublishVSExtension.js",
"argumentFormat": "",
"platforms": [
"windows"
]
},
"Node": {
"target": "PublishVSExtension.js",
"argumentFormat": "",
"platforms": [
"windows"
]
}
}
}
Binary file added BuildTasks/PublishVSExtension/tools/vswhere.exe
Binary file not shown.
Loading

0 comments on commit dc8b30a

Please sign in to comment.