Add project for Azure Pipelines Tasks for MSIX (#384)

This commit is contained in:
Luis Chacón 2020-09-24 16:03:32 -07:00 коммит произвёл GitHub
Родитель a967283997
Коммит bdb5d41520
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
161 изменённых файлов: 10862 добавлений и 0 удалений

Просмотреть файл

@ -6,3 +6,6 @@
# Utils library
/tools/utils/ @ranm-msft @msftrubengu @johnmcpms @lechacon @jamespik
# Azure Pipelines tasks
/tools/pipelines-tasks @ranm-msft @msftrubengu @johnmcpms @lechacon

27
tools/pipelines-tasks/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,27 @@
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# VSIX packaged extension
*.vsix
# Test Outputs
.taskkey
# Ignrore all compiled .js and .js.map mappings
*.js
*.js.map
# Packaged node modules
*.tgz
# PAT for publishing
pat.txt
# Powershell modules
ps_modules/

Просмотреть файл

@ -0,0 +1,5 @@
# Test timeout in milliseconds
timeout: 100000
# Test duration to flag as slow
slow: 40000

Просмотреть файл

@ -0,0 +1,104 @@
{
"loc.friendlyName": "App Installer file for MSIX",
"loc.helpMarkDown": "",
"loc.description": "Create or update an App Installer file for MSIX apps",
"loc.instanceNameFormat": "Create App Installer file",
"loc.group.displayName.optionalItems": "Optional Items",
"loc.group.displayName.dependencies": "Dependencies",
"loc.input.label.package": "Package",
"loc.input.help.package": "Path to the package or bundle.",
"loc.input.label.outputPath": "Output File Path",
"loc.input.help.outputPath": "The path of the App Installer to be written.",
"loc.input.label.method": "Method to Create App Installer File",
"loc.input.help.method": "Method used to create the App Installer file.",
"loc.input.label.existingFile": "Path to Existing App Installer File",
"loc.input.help.existingFile": "The path of the existing App Installer file to update.",
"loc.input.label.versionUpdateMethod": "Method to Update the App Installer File's Version",
"loc.input.help.versionUpdateMethod": "Increment the major/minor/build/revision of the App Installer file or enter a version number to be used.",
"loc.input.label.fileVersion": "Version for App Installer file",
"loc.input.help.fileVersion": "The version number which will be given. Must take the form (major).(minor).(build).(revision).",
"loc.input.label.uri": "URI",
"loc.input.help.uri": "Web URI to the redirected App Installer file.",
"loc.input.label.mainItemUri": "Main Package/Bundle URI",
"loc.input.help.mainItemUri": "URI to the app package/bundle location.",
"loc.input.label.updateOnLaunch": "Update On Launch",
"loc.input.help.updateOnLaunch": "Set the app to check for updates when launched.",
"loc.input.label.hoursBetweenUpdateChecks": "Hours Between Update Checks",
"loc.input.help.hoursBetweenUpdateChecks": "How often the system will check for updates to the app.",
"loc.input.label.showPromptWhenUpdating": "Show UI to User when Updating",
"loc.input.help.showPromptWhenUpdating": "Show a UI to notify the user if an update occurs when launching the app.",
"loc.input.label.updateBlocksActivation": "Update Blocks App Activation",
"loc.input.help.updateBlocksActivation": "Block the app from launching until the update finishes.",
"loc.input.label.addOptionalItem1": "Add an Optional Package/Bundle",
"loc.input.help.addOptionalItem1": "Add an optional package or bundle",
"loc.input.label.optionalItem1Name": "Optional Item 1: Name",
"loc.input.help.optionalItem1Name": "The package or bundle name of your first optional item to include.",
"loc.input.label.optionalItem1Publisher": "Optional Item 1: Publisher",
"loc.input.help.optionalItem1Publisher": "The publisher name of the first optional item to include.",
"loc.input.label.optionalItem1Version": "Optional Item 1: Version",
"loc.input.help.optionalItem1Version": "The version number of the first optional item to include.",
"loc.input.label.optionalItem1ProcessorArchitecture": "Optional Item 1: Processor Architecture",
"loc.input.help.optionalItem1ProcessorArchitecture": "The processor architecture of the first optional item to include.",
"loc.input.label.optionalItem1URI": "Optional Item 1: URI",
"loc.input.help.optionalItem1URI": "The URI of the first optional item to include.",
"loc.input.label.addOptionalItem2": "Add a Second Optional Package/Bundle",
"loc.input.help.addOptionalItem2": "Add a second optional package or bundle",
"loc.input.label.optionalItem2Name": "Optional Item 2: Name",
"loc.input.help.optionalItem2Name": "The package or bundle name of your second optional item to include.",
"loc.input.label.optionalItem2Publisher": "Optional Item 2: Publisher",
"loc.input.help.optionalItem2Publisher": "The publisher name of the second optional item to include.",
"loc.input.label.optionalItem2Version": "Optional Item 2: Version",
"loc.input.help.optionalItem2Version": "The version number of the second optional item to include.",
"loc.input.label.optionalItem2ProcessorArchitecture": "Optional Item 2: Processor Architecture",
"loc.input.help.optionalItem2ProcessorArchitecture": "The processor architecture of the second optional item to include.",
"loc.input.label.optionalItem2URI": "Optional Item 2: URI",
"loc.input.help.optionalItem2URI": "The URI of the second optional item to include.",
"loc.input.label.addOptionalItem3": "Add a Third Optional Package/Bundle",
"loc.input.help.addOptionalItem3": "Add a third optional package or bundle",
"loc.input.label.optionalItem3Name": "Optional Item 3: Name",
"loc.input.help.optionalItem3Name": "The package or bundle name of your third optional item to include.",
"loc.input.label.optionalItem3Publisher": "Optional Item 3: Publisher",
"loc.input.help.optionalItem3Publisher": "The publisher name of the third optional item to include.",
"loc.input.label.optionalItem3Version": "Optional Item 3: Version",
"loc.input.help.optionalItem3Version": "The version number of the third optional item to include.",
"loc.input.label.optionalItem3ProcessorArchitecture": "Optional Item 3: Processor Architecture",
"loc.input.help.optionalItem3ProcessorArchitecture": "The processor architecture of the third optional item to include.",
"loc.input.label.optionalItem3URI": "Optional Item 3: URI",
"loc.input.help.optionalItem3URI": "The URI of the third optional item to include.",
"loc.input.label.addDependency1": "Add a Dependency",
"loc.input.help.addDependency1": "Add a dependency.",
"loc.input.label.dependency1Name": "Dependency 1: Name",
"loc.input.help.dependency1Name": "The name of the first dependency to include.",
"loc.input.label.dependency1Publisher": "Dependency 1: Publisher",
"loc.input.help.dependency1Publisher": "The publisher name of the first dependency to include.",
"loc.input.label.dependency1Version": "Dependency 1: Version",
"loc.input.help.dependency1Version": "The version number of the first dependency to include.",
"loc.input.label.dependency1ProcessorArchitecture": "Dependency 1: Processor Architecture",
"loc.input.help.dependency1ProcessorArchitecture": "The processor architecture of the first dependency to include.",
"loc.input.label.dependency1URI": "Dependency 1: URI",
"loc.input.help.dependency1URI": "The URI of the first dependency to include.",
"loc.input.label.addDependency2": "Add a Second Dependency",
"loc.input.help.addDependency2": "Add a second dependency.",
"loc.input.label.dependency2Name": "Dependency 2: Name",
"loc.input.help.dependency2Name": "The name of the second dependency to include.",
"loc.input.label.dependency2Publisher": "Dependency 2: Publisher",
"loc.input.help.dependency2Publisher": "The publisher name of the second dependency to include.",
"loc.input.label.dependency2Version": "Dependency 2: Version",
"loc.input.help.dependency2Version": "The version number of the second dependency to include.",
"loc.input.label.dependency2ProcessorArchitecture": "Dependency 2: Processor Architecture",
"loc.input.help.dependency2ProcessorArchitecture": "The processor architecture of the second dependency to include.",
"loc.input.label.dependency2URI": "Dependency 2: URI",
"loc.input.help.dependency2URI": "The URI of the second dependency to include.",
"loc.input.label.addDependency3": "Add a Third Dependency",
"loc.input.help.addDependency3": "Add a third dependency.",
"loc.input.label.dependency3Name": "Dependency 3: Name",
"loc.input.help.dependency3Name": "The name of the third dependency to include.",
"loc.input.label.dependency3Publisher": "Dependency 3: Publisher",
"loc.input.help.dependency3Publisher": "The publisher name of the third dependency to include.",
"loc.input.label.dependency3Version": "Dependency 3: Version",
"loc.input.help.dependency3Version": "The version number of the third dependency to include.",
"loc.input.label.dependency3ProcessorArchitecture": "Dependency 3: Processor Architecture",
"loc.input.help.dependency3ProcessorArchitecture": "The processor architecture of the third dependency to include.",
"loc.input.label.dependency3URI": "Dependency 3: URI",
"loc.input.help.dependency3URI": "The URI of the third dependency to include."
}

Просмотреть файл

@ -0,0 +1,186 @@
import helpers = require('common/helpers');
/* This file contains helpers for creating or modifying an .appinstaller file */
export interface UpdateParameters
{
existingFile: string,
versionUpdateMethod: string,
fileVersion?: string
}
export interface CreateParameters
{
uri: string,
fileVersion: string,
mainItemUri: string,
updateOnLaunch: boolean,
hoursBetweenUpdateChecks?: string,
showPromptWhenUpdating?: boolean,
updateBlocksActivation?: boolean,
optionalItems: PackageOrBundle[],
dependencies: PackageOrBundle[]
}
// Identity information about a package and bundle.
// This can represent a main item, an optional item or a dependency.
// The inner property is used to produce the XML, so the names of the
// properties must be kept named exactly as they are.
export interface PackageOrBundle
{
isBundle: boolean,
packageOrBundle:
{
Name: string,
Publisher: string,
Version: string,
ProcessorArchitecture?: string,
Uri: string
}
}
/**
* Update the version of the App Installer file.
* Save the new App Installer file to outputPath.
* @param outputPath the path to save the new App Installer content to
* @param existingFile the path to the existing App Installer file that needs updating
* @param versionUpdateMethod how to update the version of the file
* @param fileVersion new version of the file, if the update method is manual
* @param mainApp identity of the main app, used to update the version
*/
export const updateExisting = async (
outputPath: string,
{
existingFile,
versionUpdateMethod,
fileVersion
}: UpdateParameters,
mainApp: PackageOrBundle) =>
{
const appInstallerFile = await helpers.parseXml(existingFile);
let newFileVersion: string;
if (versionUpdateMethod !== 'manual')
{
const existingFileVersion: string[] = appInstallerFile.AppInstaller.$.Version.split('.');
newFileVersion = helpers.incrementVersion(existingFileVersion, versionUpdateMethod);
}
else
{
newFileVersion = fileVersion!;
}
// Update the version of the file.
appInstallerFile.AppInstaller.$.Version = newFileVersion;
// Update the version of the main app
const tagToEdit: string = mainApp.isBundle ? 'MainBundle' : 'MainPackage';
appInstallerFile.AppInstaller[tagToEdit][0].$.Version = mainApp.packageOrBundle.Version;
helpers.writeXml(appInstallerFile, outputPath);
}
const getXmlElementsForItems = (items: PackageOrBundle[]): any =>
{
const packages: any[] = [];
const bundles: any[] = [];
for (const item of items)
{
// The properties of the package/bundle are stored as attributes in the XML
const xmlItem = { $: item.packageOrBundle };
if (item.isBundle)
{
bundles.push(xmlItem);
}
else
{
packages.push(xmlItem);
}
}
const element: any = {};
if (bundles.length > 0)
{
element.Bundle = bundles;
}
if (packages.length > 0)
{
element.Package = packages;
}
return element;
}
export const createNew = (
outputPath:string,
{
fileVersion,
uri,
optionalItems,
dependencies,
updateOnLaunch,
hoursBetweenUpdateChecks,
showPromptWhenUpdating,
updateBlocksActivation
}: CreateParameters,
mainApp: PackageOrBundle) =>
{
// Object representing the new XML file.
// All of the property names here must be keep exactly as they are, as they will be translated to XML.
// Initialize it with the root element.
const newFile: any = { AppInstaller: {} };
// Attributes of <AppInstaller>
newFile.AppInstaller.$ = {
xmlns: 'http://schemas.microsoft.com/appx/appinstaller/2018',
Version: fileVersion,
Uri: uri
};
// MainPackage/MainBundle
newFile.AppInstaller[mainApp.isBundle ? 'MainBundle' : 'MainPackage'] =
{
$: mainApp.packageOrBundle
}
// Optional items
if (optionalItems.length > 0)
{
newFile.AppInstaller.OptionalPackages = getXmlElementsForItems(optionalItems);
}
// Dependencies
if (dependencies.length > 0)
{
newFile.AppInstaller.Dependencies = getXmlElementsForItems(dependencies);
}
// Update settings
if (updateOnLaunch)
{
const onLaunchSettings: any = {};
newFile.AppInstaller.UpdateSettings =
{
OnLaunch: onLaunchSettings
};
if (hoursBetweenUpdateChecks)
{
onLaunchSettings.HoursBetweenUpdateChecks = hoursBetweenUpdateChecks;
}
if (showPromptWhenUpdating)
{
onLaunchSettings.ShowPrompt = showPromptWhenUpdating;
}
if (updateBlocksActivation)
{
onLaunchSettings.UpdateBlocksActivation = updateBlocksActivation;
}
}
helpers.writeXml(newFile, outputPath);
}

Просмотреть файл

@ -0,0 +1,32 @@
# Set the task's inputs here to use when debugging
INPUT_PACKAGE=test\assets\existingPackage.msix
INPUT_OUTPUTPATH=debug\app.appinstaller
INPUT_EXISTINGFILE=test\assets\existingAppInstallerFile.appinstaller
INPUT_METHOD=create
INPUT_VERSIONUPDATEMETHOD=major
INPUT_FILEVERSION=1.0.0.1
INPUT_URI=https://example.com
INPUT_MAINITEMURI=https://example.com
INPUT_UPDATEONLAUNCH=true
INPUT_HOURSBETWEENUPDATECHECKS=24
INPUT_ADDOPTIONALITEM1=package
INPUT_OPTIONALITEM1NAME=OptionalItem1
INPUT_OPTIONALITEM1PUBLISHER=CN=Publisher1
INPUT_OPTIONALITEM1VERSION=1.0.0.0
INPUT_OPTIONALITEM1PROCESSORARCHITECTURE=x86
INPUT_OPTIONALITEM1URI=https://example.com
INPUT_ADDOPTIONALITEM2=bundle
INPUT_OPTIONALITEM2NAME=OptionalItem2
INPUT_OPTIONALITEM2PUBLISHER=CN=Publisher2
INPUT_OPTIONALITEM2VERSION=2.0.0.0
INPUT_OPTIONALITEM2URI=https://example.com
INPUT_ADDOPTIONALITEM3=bundle
INPUT_OPTIONALITEM3NAME=OptionalItem2
INPUT_OPTIONALITEM3PUBLISHER=CN=Publisher3
INPUT_OPTIONALITEM3VERSION=3.0.0.0
INPUT_OPTIONALITEM3URI=https://example.com
INPUT_ADDDEPENDENCY1=none

Двоичные данные
tools/pipelines-tasks/AppInstallerFile/icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Просмотреть файл

@ -0,0 +1,213 @@
import path = require('path');
import tl = require('azure-pipelines-task-lib/task')
import helpers = require('common/helpers');
import appInstallerFile = require('./appinstallerfile');
interface Inputs {
packagePath: string,
outputPath: string,
method: string,
inputsForUpdate?: appInstallerFile.UpdateParameters,
inputsForCreate?: appInstallerFile.CreateParameters
}
const readInputsForItem = (inputPrefix: string, isBundle: boolean): appInstallerFile.PackageOrBundle =>
{
const Name: string = helpers.getInputWithErrorCheck(`${inputPrefix}Name`, `Input Error: ${inputPrefix} missing name.`);
const Publisher: string = helpers.getInputWithErrorCheck(`${inputPrefix}Publisher`, `Input Error: ${inputPrefix} missing publisher.`);
const Version: string = helpers.getInputWithErrorCheck(`${inputPrefix}Version`, `Input Error: ${inputPrefix} missing version.`);
const ProcessorArchitecture: string | undefined = tl.getInput(`${inputPrefix}ProcessorArchitecture`);
const Uri: string = helpers.getInputWithErrorCheck(`${inputPrefix}URI`, `Input Error: ${inputPrefix} missing URI.`);
return { isBundle, packageOrBundle: { Name, Publisher, Version, ProcessorArchitecture, Uri } };
}
const readInputsForCreate = (): appInstallerFile.CreateParameters =>
{
const uri: string = helpers.getInputWithErrorCheck('uri', 'The App Installer file URI is required but none was given');
const fileVersion: string = helpers.getInputWithErrorCheck('fileVersion', 'The App Installer file version is required but none was given');
const mainItemUri: string = helpers.getInputWithErrorCheck('mainItemUri', 'The URI of the main package/bundle is required but none was given');
const updateOnLaunch: boolean = tl.getBoolInput('updateOnLaunch');
let hoursBetweenUpdateChecks: string | undefined;
let showPromptWhenUpdating: boolean | undefined;
let updateBlocksActivation: boolean | undefined;
if (updateOnLaunch)
{
hoursBetweenUpdateChecks = tl.getInput('hoursBetweenUpdateChecks');
showPromptWhenUpdating = tl.getBoolInput('showPromptWhenUpdating');
if (showPromptWhenUpdating)
{
updateBlocksActivation = tl.getBoolInput('updateBlocksActivation');
}
}
const optionalItems: appInstallerFile.PackageOrBundle[] = [];
const maximumOptionalItems: number = 3;
for (let i = 1; i <= maximumOptionalItems; i++)
{
const optionalItemType: string | undefined = tl.getInput(`addOptionalItem${i}`);
const optionalItemInputPrefix: string = `optionalItem${i}`;
if (optionalItemType === 'package')
{
optionalItems.push(readInputsForItem(optionalItemInputPrefix, /* isBundle */ false));
}
else if (optionalItemType === 'bundle')
{
optionalItems.push(readInputsForItem(optionalItemInputPrefix, /* isBundle */ true));
}
}
const dependencies: appInstallerFile.PackageOrBundle[] = [];
const maximumDependencies: number = 3;
for (let i = 1; i <= maximumDependencies; i++)
{
const dependencyType: string | undefined = tl.getInput(`addDependency${i}`);
const dependencyInputPrefix: string = `dependency${i}`;
if (dependencyType === 'package')
{
dependencies.push(readInputsForItem(dependencyInputPrefix, /* isBundle */ false));
}
else if (dependencyType === 'bundle')
{
dependencies.push(readInputsForItem(dependencyInputPrefix, /* isBundle */ true));
}
}
return {
uri,
fileVersion,
mainItemUri,
updateOnLaunch,
hoursBetweenUpdateChecks,
showPromptWhenUpdating,
updateBlocksActivation,
optionalItems,
dependencies
}
}
const readInputsForUpdate = (): appInstallerFile.UpdateParameters =>
{
const existingFile: string = helpers.getInputWithErrorCheck('existingFile', 'The path to the existing App Installer file that requires updating is required, but none was given.');
const versionUpdateMethod: string = helpers.getInputWithErrorCheck('versionUpdateMethod', 'An update method is required to update the version but none was given.');
let fileVersion: string | undefined;
if (versionUpdateMethod === 'manual')
{
fileVersion = helpers.getInputWithErrorCheck('fileVersionUpdateMethod', 'To manually update the version, a version is needed but none was given.');
}
return { existingFile, versionUpdateMethod, fileVersion };
}
/**
* @returns A dictionary with the task arguments.
*/
const readInputs = (): Inputs =>
{
const packagePath: string = helpers.getInputWithErrorCheck('package', 'Path to the package or bundle is required');
const outputPath: string = helpers.getInputWithErrorCheck('outputPath', 'A name is required to save the App Installer to once created, but none was given');
const method: string = helpers.getInputWithErrorCheck('method', 'Method for generating the App Installer file is required.')
let inputsForCreate: appInstallerFile.CreateParameters | undefined;
let inputsForUpdate: appInstallerFile.UpdateParameters | undefined;
if (method === 'create')
{
inputsForCreate = readInputsForCreate();
}
else if (method === 'update')
{
inputsForUpdate = readInputsForUpdate();
}
return { packagePath, outputPath, method, inputsForCreate, inputsForUpdate };
}
/**
* Returns the parsed manifest (appxmanifest.xml for a package or appxbundlemanifest.xml
* for a bundle) by unpacking the package or bundle. This will unpack it, parse the
* manifest and delete the unpack directory.
* @param packagePath path to the package to inspect
* @param isBundle whether or not the given App is a bundle
*/
const getAppxManifestPathFromApp = async (packagePath: string, isBundle: boolean): Promise<any> =>
{
const packageName: string = path.parse(packagePath).name;
const extractionDirectory: string = path.join(helpers.getTempDirectory(), packageName);
try
{
tl.debug(`Unpacking ${packagePath} to `);
await helpers.unpackFile(packagePath, extractionDirectory, isBundle);
let appxManifestPath: string;
// here, we want to want to detect if the given app
// is an MSIX package or bundle, specifically, if it's a bundle,
// we need to look for a folder called AppxMetadata which should
// contain the appxbundlemanifest.xml file
if (isBundle)
{
appxManifestPath = path.join(extractionDirectory, 'AppxMetadata', 'AppxBundleManifest.xml');
}
else
{
// if it's just a package then the directory which we unpacked the
// content to should contain the appxmanifest.xml file
appxManifestPath = path.join(extractionDirectory, 'AppxManifest.xml');
}
return await helpers.parseXml(appxManifestPath);
}
finally
{
tl.rmRF(extractionDirectory);
}
}
const getAppInformationFromPackage = async (packagePath: string): Promise<appInstallerFile.PackageOrBundle> =>
{
const extension: string = path.extname(packagePath).toLowerCase();
const isBundle: boolean = extension === '.appxbundle' || extension === '.msixbundle';
// Read the manifest
const manifest = await getAppxManifestPathFromApp(packagePath, isBundle);
if (isBundle)
{
return { isBundle, packageOrBundle: manifest.Bundle.Identity[0].$ };
}
else
{
return { isBundle, packageOrBundle: manifest.Package.Identity[0].$ };
}
}
/**
* Main function for the task.
*/
const run = async () =>
{
tl.setResourcePath(path.join(__dirname, 'task.json'));
const inputs: Inputs = readInputs();
// Get app info from the manifest in the app to use in the App Installer file
const appInformation: appInstallerFile.PackageOrBundle = await getAppInformationFromPackage(inputs.packagePath);
if (inputs.method === 'create')
{
// The main item was read from the package and does not yet have an URI
appInformation.packageOrBundle.Uri = inputs.inputsForCreate!.mainItemUri;
appInstallerFile.createNew(inputs.outputPath, inputs.inputsForCreate!, appInformation);
}
else if (inputs.method === 'update')
{
await appInstallerFile.updateExisting(inputs.outputPath, inputs.inputsForUpdate!, appInformation);
}
}
run().catch(err =>
{
tl.setResult(tl.TaskResult.Failed, err.message);
})

286
tools/pipelines-tasks/AppInstallerFile/package-lock.json сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,286 @@
{
"name": "msix-tasks-app-installer-file",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/node": {
"version": "14.6.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.3.tgz",
"integrity": "sha512-pC/hkcREG6YfDfui1FBmj8e20jFU5Exjw4NYDm8kEdrW+mOh0T1Zve8DWKnS7ZIZvgncrctcNCXF4Q2I+loyww=="
},
"@types/xml2js": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.5.tgz",
"integrity": "sha512-yohU3zMn0fkhlape1nxXG2bLEGZRc1FeqF80RoHaYXJN7uibaauXfhzhOJr1Xh36sn+/tx21QAOf07b/xYVk1w==",
"requires": {
"@types/node": "*"
}
},
"adm-zip": {
"version": "0.4.16",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz",
"integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg=="
},
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"azure-devops-node-api": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-10.1.1.tgz",
"integrity": "sha512-P4Hyrh/+Nzc2KXQk73z72/GsenSWIH5o8uiyELqykJYs9TWTVCxVwghoR7lPeiY6QVoXkq2S2KtvAgi5fyjl9w==",
"requires": {
"tunnel": "0.0.6",
"typed-rest-client": "^1.7.3",
"underscore": "1.8.3"
}
},
"azure-pipelines-task-lib": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.10.0.tgz",
"integrity": "sha512-nmwf4ReXGfaBDMRO08/KSDOqbieJFljQSXd6bSFl28QsOKiGy5qz1O7pMnb9UqYfH5Fbro0zU4Q88hpO0XkFHg==",
"requires": {
"minimatch": "3.0.4",
"mockery": "^1.7.0",
"q": "^1.1.2",
"semver": "^5.1.0",
"shelljs": "^0.3.0",
"sync-request": "3.0.1",
"uuid": "^3.0.1"
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
},
"caseless": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
"integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c="
},
"common": {
"version": "file:../common/msix-tasks-helpers-1.0.0.tgz",
"integrity": "sha512-JqVtP3csFwsJmfeEfendFrjUE4R53/jVf1NIpB7at7SYM9dEXYvCibctQUztM58vqwJ7/Bh6Io/Gbd7mW677zQ==",
"requires": {
"@types/xml2js": "^0.4.5",
"adm-zip": "^0.4.16",
"azure-devops-node-api": "^10.1.1",
"azure-pipelines-task-lib": "^2.9.5",
"xml2js": "^0.4.23"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"http-basic": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/http-basic/-/http-basic-2.5.1.tgz",
"integrity": "sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=",
"requires": {
"caseless": "~0.11.0",
"concat-stream": "^1.4.6",
"http-response-object": "^1.0.0"
}
},
"http-response-object": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-1.1.0.tgz",
"integrity": "sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM="
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"mockery": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/mockery/-/mockery-1.7.0.tgz",
"integrity": "sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "~2.0.3"
}
},
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
},
"qs": {
"version": "6.9.4",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
"integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ=="
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"shelljs": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
"integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"sync-request": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/sync-request/-/sync-request-3.0.1.tgz",
"integrity": "sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=",
"requires": {
"concat-stream": "^1.4.7",
"http-response-object": "^1.0.1",
"then-request": "^2.0.1"
}
},
"then-request": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/then-request/-/then-request-2.2.0.tgz",
"integrity": "sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=",
"requires": {
"caseless": "~0.11.0",
"concat-stream": "^1.4.7",
"http-basic": "^2.5.1",
"http-response-object": "^1.1.0",
"promise": "^7.1.1",
"qs": "^6.1.0"
}
},
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"typed-rest-client": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.7.3.tgz",
"integrity": "sha512-CwTpx/TkRHGZoHkJhBcp4X8K3/WtlzSHVQR0OIFnt10j4tgy4ypgq/SrrgVpA1s6tAL49Q6J3R5C0Cgfh2ddqA==",
"requires": {
"qs": "^6.9.1",
"tunnel": "0.0.6",
"underscore": "1.8.3"
}
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"underscore": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
},
"xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"requires": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
}
},
"xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
}
}
}

Просмотреть файл

@ -0,0 +1,20 @@
{
"name": "msix-tasks-app-installer-file",
"version": "1.0.0",
"description": "Task to create or update an App Installer file",
"repository": {
"type": "git",
"url": "git+github.com/microsoft/msix-ado-tasks-extension.git"
},
"scripts": {},
"author": "Microsoft Coporation",
"license": "MIT",
"dependencies": {
"azure-devops-node-api": "^10.1.1",
"azure-pipelines-task-lib": "^2.9.5",
"common": "file:../common/msix-tasks-helpers-1.0.0.tgz"
},
"devDependencies": {
"@types/node": "^14.0.5"
}
}

Просмотреть файл

@ -0,0 +1,508 @@
{
"$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
"id": "ced3bc79-ea98-4c51-8a83-ed4e3a0a77ed",
"name": "AppInstallerFile",
"friendlyName": "App Installer file for MSIX",
"instanceNameFormat": "Create App Installer file",
"description": "Create or update an App Installer file for MSIX apps",
"author": "Microsoft Corporation",
"category": "Package",
"helpMarkDown": "",
"execution": {
"Node10": {
"target": "index.js"
}
},
"version": {
"Major": 1,
"Minor": 0,
"Patch": 0
},
"minimumAgentVersion": "1.95.0",
"groups": [
{
"name": "optionalItems",
"displayName": "Optional Items",
"isExpanded": false
},
{
"name": "dependencies",
"displayName": "Dependencies",
"isExpanded": false
}
],
"inputs": [
{
"name": "package",
"type": "string",
"label": "Package",
"required": true,
"helpMarkDown": "Path to the package or bundle."
},
{
"name": "outputPath",
"type": "string",
"label": "Output File Path",
"defaultValue": "",
"required": true,
"helpMarkDown": "The path of the App Installer to be written."
},
{
"name": "method",
"type": "pickList",
"label": "Method to Create App Installer File",
"defaultValue": "create",
"required": true,
"helpMarkDown": "Method used to create the App Installer file.",
"options": {
"create": "Create a new App Installer file",
"update": "Update an existing App Installer file"
}
},
{
"name": "existingFile",
"type": "filePath",
"label": "Path to Existing App Installer File",
"required": true,
"helpMarkDown": "The path of the existing App Installer file to update.",
"visibleRule": "method = update"
},
{
"name": "versionUpdateMethod",
"type": "pickList",
"label": "Method to Update the App Installer File's Version",
"required": true,
"defaultValue": "revision",
"helpMarkDown": "Increment the major/minor/build/revision of the App Installer file or enter a version number to be used.",
"options": {
"manual": "Manual Version",
"major": "Incremenet Major",
"minor": "Increment Minor",
"build": "Increment Build",
"revision": "Increment Revision"
},
"visibleRule": "method = update"
},
{
"name": "fileVersion",
"type": "string",
"label": "Version for App Installer file",
"required": true,
"defaultValue": "1.0.0.0",
"helpMarkDown": "The version number which will be given. Must take the form (major).(minor).(build).(revision).",
"visibleRule": "method = create || versionUpdateMethod = manual"
},
{
"name": "uri",
"type": "string",
"label": "URI",
"required": true,
"helpMarkDown": "Web URI to the redirected App Installer file.",
"visibleRule": "method = create"
},
{
"name": "mainItemUri",
"type": "string",
"label": "Main Package/Bundle URI",
"required": true,
"helpMarkDown": "URI to the app package/bundle location.",
"visibleRule": "method = create"
},
{
"name": "updateOnLaunch",
"type": "boolean",
"label": "Update On Launch",
"defaultValue": true,
"required": false,
"helpMarkDown": "Set the app to check for updates when launched.",
"visibleRule": "method = create"
},
{
"name": "hoursBetweenUpdateChecks",
"type": "string",
"label": "Hours Between Update Checks",
"defaultValue": "24",
"required": false,
"helpMarkDown": "How often the system will check for updates to the app.",
"visibleRule": "method = create && updateOnLaunch = true"
},
{
"name": "showPromptWhenUpdating",
"type": "boolean",
"label": "Show UI to User when Updating",
"defaultValue": false,
"required": false,
"helpMarkDown": "Show a UI to notify the user if an update occurs when launching the app.",
"visibleRule": "method = create && updateOnLaunch = true"
},
{
"name": "updateBlocksActivation",
"type": "boolean",
"label": "Update Blocks App Activation",
"defaultValue": false,
"required": false,
"helpMarkDown": "Block the app from launching until the update finishes.",
"visibleRule": "method = create && updateOnLaunch = true && showPromptWhenUpdating = true"
},
{
"name": "addOptionalItem1",
"type": "pickList",
"label": "Add an Optional Package/Bundle",
"defaultValue": "none",
"required": false,
"groupName": "optionalItems",
"helpMarkDown": "Add an optional package or bundle",
"visibleRule": "method = create",
"options": {
"none": "No Optional Package/Bundle",
"package": "Add Optional Package",
"bundle": "Add Optional Bundle"
}
},
{
"name": "optionalItem1Name",
"type": "string",
"label": "Optional Item 1: Name",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The package or bundle name of your first optional item to include.",
"visibleRule": "method = create && addOptionalItem1 != none"
},
{
"name": "optionalItem1Publisher",
"type": "string",
"label": "Optional Item 1: Publisher",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The publisher name of the first optional item to include.",
"visibleRule": "method = create && addOptionalItem1 != none"
},
{
"name": "optionalItem1Version",
"type": "string",
"label": "Optional Item 1: Version",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The version number of the first optional item to include.",
"visibleRule": "method = create && addOptionalItem1 != none"
},
{
"name": "optionalItem1ProcessorArchitecture",
"type": "string",
"label": "Optional Item 1: Processor Architecture",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The processor architecture of the first optional item to include.",
"visibleRule": "method = create && addOptionalItem1 != none"
},
{
"name": "optionalItem1URI",
"type": "string",
"label": "Optional Item 1: URI",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The URI of the first optional item to include.",
"visibleRule": "method = create && addOptionalItem1 != none"
},
{
"name": "addOptionalItem2",
"type": "pickList",
"label": "Add a Second Optional Package/Bundle",
"defaultValue": "none",
"required": false,
"groupName": "optionalItems",
"helpMarkDown": "Add a second optional package or bundle",
"visibleRule": "method = create && addOptionalItem1 != none",
"options": {
"none": "No Optional Package/Bundle",
"package": "Add Optional Package",
"bundle": "Add Optional Bundle"
}
},
{
"name": "optionalItem2Name",
"type": "string",
"label": "Optional Item 2: Name",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The package or bundle name of your second optional item to include.",
"visibleRule": "method = create && addOptionalItem2 != none"
},
{
"name": "optionalItem2Publisher",
"type": "string",
"label": "Optional Item 2: Publisher",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The publisher name of the second optional item to include.",
"visibleRule": "method = create && addOptionalItem2 != none"
},
{
"name": "optionalItem2Version",
"type": "string",
"label": "Optional Item 2: Version",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The version number of the second optional item to include.",
"visibleRule": "method = create && addOptionalItem2 != none"
},
{
"name": "optionalItem2ProcessorArchitecture",
"type": "string",
"label": "Optional Item 2: Processor Architecture",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The processor architecture of the second optional item to include.",
"visibleRule": "method = create && addOptionalItem2 != none"
},
{
"name": "optionalItem2URI",
"type": "string",
"label": "Optional Item 2: URI",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The URI of the second optional item to include.",
"visibleRule": "method = create && addOptionalItem2 != none"
},
{
"name": "addOptionalItem3",
"type": "pickList",
"label": "Add a Third Optional Package/Bundle",
"defaultValue": "none",
"required": false,
"groupName": "optionalItems",
"helpMarkDown": "Add a third optional package or bundle",
"visibleRule": "method = create && addOptionalItem2 != none",
"options": {
"none": "No Optional Package/Bundle",
"package": "Add Optional Package",
"bundle": "Add Optional Bundle"
}
},
{
"name": "optionalItem3Name",
"type": "string",
"label": "Optional Item 3: Name",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The package or bundle name of your third optional item to include.",
"visibleRule": "method = create && addOptionalItem3 != none"
},
{
"name": "optionalItem3Publisher",
"type": "string",
"label": "Optional Item 3: Publisher",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The publisher name of the third optional item to include.",
"visibleRule": "method = create && addOptionalItem3 != none"
},
{
"name": "optionalItem3Version",
"type": "string",
"label": "Optional Item 3: Version",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The version number of the third optional item to include.",
"visibleRule": "method = create && addOptionalItem3 != none"
},
{
"name": "optionalItem3ProcessorArchitecture",
"type": "string",
"label": "Optional Item 3: Processor Architecture",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The processor architecture of the third optional item to include.",
"visibleRule": "method = create && addOptionalItem3 != none"
},
{
"name": "optionalItem3URI",
"type": "string",
"label": "Optional Item 3: URI",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "The URI of the third optional item to include.",
"visibleRule": "method = create && addOptionalItem3 != none"
},
{
"name": "addDependency1",
"type": "pickList",
"label": "Add a Dependency",
"defaultValue": "none",
"required": false,
"groupName": "dependencies",
"helpMarkDown": "Add a dependency.",
"visibleRule": "method = create",
"options": {
"none": "No Dependency",
"package": "Add Package Dependency",
"bundle": "Add Bundle Dependency"
}
},
{
"name": "dependency1Name",
"type": "string",
"label": "Dependency 1: Name",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The name of the first dependency to include.",
"visibleRule": "method = create && addDependency1 != none"
},
{
"name": "dependency1Publisher",
"type": "string",
"label": "Dependency 1: Publisher",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The publisher name of the first dependency to include.",
"visibleRule": "method = create && addDependency1 != none"
},
{
"name": "dependency1Version",
"type": "string",
"label": "Dependency 1: Version",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The version number of the first dependency to include.",
"visibleRule": "method = create && addDependency1 != none"
},
{
"name": "dependency1ProcessorArchitecture",
"type": "string",
"label": "Dependency 1: Processor Architecture",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The processor architecture of the first dependency to include.",
"visibleRule": "method = create && addDependency1 != none"
},
{
"name": "dependency1URI",
"type": "string",
"label": "Dependency 1: URI",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The URI of the first dependency to include.",
"visibleRule": "method = create && addDependency1 != none"
},
{
"name": "addDependency2",
"type": "pickList",
"label": "Add a Second Dependency",
"defaultValue": "none",
"required": false,
"groupName": "dependencies",
"helpMarkDown": "Add a second dependency.",
"visibleRule": "method = create && addDependency1 != none",
"options": {
"none": "No Dependency",
"package": "Add Package Dependency",
"bundle": "Add Bundle Dependency"
}
},
{
"name": "dependency2Name",
"type": "string",
"label": "Dependency 2: Name",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The name of the second dependency to include.",
"visibleRule": "method = create && addDependency2 != none"
},
{
"name": "dependency2Publisher",
"type": "string",
"label": "Dependency 2: Publisher",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The publisher name of the second dependency to include.",
"visibleRule": "method = create && addDependency2 != none"
},
{
"name": "dependency2Version",
"type": "string",
"label": "Dependency 2: Version",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The version number of the second dependency to include.",
"visibleRule": "method = create && addDependency2 != none"
},
{
"name": "dependency2ProcessorArchitecture",
"type": "string",
"label": "Dependency 2: Processor Architecture",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The processor architecture of the second dependency to include.",
"visibleRule": "method = create && addDependency2 != none"
},
{
"name": "dependency2URI",
"type": "string",
"label": "Dependency 2: URI",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The URI of the second dependency to include.",
"visibleRule": "method = create && addDependency2 != none"
},
{
"name": "addDependency3",
"type": "pickList",
"label": "Add a Third Dependency",
"defaultValue": "none",
"required": false,
"groupName": "dependencies",
"helpMarkDown": "Add a third dependency.",
"visibleRule": "method = create && addDependency2 != none",
"options": {
"none": "No Dependency",
"package": "Add Package Dependency",
"bundle": "Add Bundle Dependency"
}
},
{
"name": "dependency3Name",
"type": "string",
"label": "Dependency 3: Name",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The name of the third dependency to include.",
"visibleRule": "method = create && addDependency3 != none"
},
{
"name": "dependency3Publisher",
"type": "string",
"label": "Dependency 3: Publisher",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The publisher name of the third dependency to include.",
"visibleRule": "method = create && addDependency3 != none"
},
{
"name": "dependency3Version",
"type": "string",
"label": "Dependency 3: Version",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The version number of the third dependency to include.",
"visibleRule": "method = create && addDependency3 != none"
},
{
"name": "dependency3ProcessorArchitecture",
"type": "string",
"label": "Dependency 3: Processor Architecture",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The processor architecture of the third dependency to include.",
"visibleRule": "method = create && addDependency3 != none"
},
{
"name": "dependency3URI",
"type": "string",
"label": "Dependency 3: URI",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "The URI of the third dependency to include.",
"visibleRule": "method = create && addDependency3 != none"
}
]
}

Просмотреть файл

@ -0,0 +1,508 @@
{
"$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
"id": "ced3bc79-ea98-4c51-8a83-ed4e3a0a77ed",
"name": "AppInstallerFile",
"friendlyName": "ms-resource:loc.friendlyName",
"instanceNameFormat": "ms-resource:loc.instanceNameFormat",
"description": "ms-resource:loc.description",
"author": "Microsoft Corporation",
"category": "Package",
"helpMarkDown": "ms-resource:loc.helpMarkDown",
"execution": {
"Node10": {
"target": "index.js"
}
},
"version": {
"Major": 1,
"Minor": 0,
"Patch": 0
},
"minimumAgentVersion": "1.95.0",
"groups": [
{
"name": "optionalItems",
"displayName": "ms-resource:loc.group.displayName.optionalItems",
"isExpanded": false
},
{
"name": "dependencies",
"displayName": "ms-resource:loc.group.displayName.dependencies",
"isExpanded": false
}
],
"inputs": [
{
"name": "package",
"type": "string",
"label": "ms-resource:loc.input.label.package",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.package"
},
{
"name": "outputPath",
"type": "string",
"label": "ms-resource:loc.input.label.outputPath",
"defaultValue": "",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.outputPath"
},
{
"name": "method",
"type": "pickList",
"label": "ms-resource:loc.input.label.method",
"defaultValue": "create",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.method",
"options": {
"create": "Create a new App Installer file",
"update": "Update an existing App Installer file"
}
},
{
"name": "existingFile",
"type": "filePath",
"label": "ms-resource:loc.input.label.existingFile",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.existingFile",
"visibleRule": "method = update"
},
{
"name": "versionUpdateMethod",
"type": "pickList",
"label": "ms-resource:loc.input.label.versionUpdateMethod",
"required": true,
"defaultValue": "revision",
"helpMarkDown": "ms-resource:loc.input.help.versionUpdateMethod",
"options": {
"manual": "Manual Version",
"major": "Incremenet Major",
"minor": "Increment Minor",
"build": "Increment Build",
"revision": "Increment Revision"
},
"visibleRule": "method = update"
},
{
"name": "fileVersion",
"type": "string",
"label": "ms-resource:loc.input.label.fileVersion",
"required": true,
"defaultValue": "1.0.0.0",
"helpMarkDown": "ms-resource:loc.input.help.fileVersion",
"visibleRule": "method = create || versionUpdateMethod = manual"
},
{
"name": "uri",
"type": "string",
"label": "ms-resource:loc.input.label.uri",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.uri",
"visibleRule": "method = create"
},
{
"name": "mainItemUri",
"type": "string",
"label": "ms-resource:loc.input.label.mainItemUri",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.mainItemUri",
"visibleRule": "method = create"
},
{
"name": "updateOnLaunch",
"type": "boolean",
"label": "ms-resource:loc.input.label.updateOnLaunch",
"defaultValue": true,
"required": false,
"helpMarkDown": "ms-resource:loc.input.help.updateOnLaunch",
"visibleRule": "method = create"
},
{
"name": "hoursBetweenUpdateChecks",
"type": "string",
"label": "ms-resource:loc.input.label.hoursBetweenUpdateChecks",
"defaultValue": "24",
"required": false,
"helpMarkDown": "ms-resource:loc.input.help.hoursBetweenUpdateChecks",
"visibleRule": "method = create && updateOnLaunch = true"
},
{
"name": "showPromptWhenUpdating",
"type": "boolean",
"label": "ms-resource:loc.input.label.showPromptWhenUpdating",
"defaultValue": false,
"required": false,
"helpMarkDown": "ms-resource:loc.input.help.showPromptWhenUpdating",
"visibleRule": "method = create && updateOnLaunch = true"
},
{
"name": "updateBlocksActivation",
"type": "boolean",
"label": "ms-resource:loc.input.label.updateBlocksActivation",
"defaultValue": false,
"required": false,
"helpMarkDown": "ms-resource:loc.input.help.updateBlocksActivation",
"visibleRule": "method = create && updateOnLaunch = true && showPromptWhenUpdating = true"
},
{
"name": "addOptionalItem1",
"type": "pickList",
"label": "ms-resource:loc.input.label.addOptionalItem1",
"defaultValue": "none",
"required": false,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.addOptionalItem1",
"visibleRule": "method = create",
"options": {
"none": "No Optional Package/Bundle",
"package": "Add Optional Package",
"bundle": "Add Optional Bundle"
}
},
{
"name": "optionalItem1Name",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem1Name",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem1Name",
"visibleRule": "method = create && addOptionalItem1 != none"
},
{
"name": "optionalItem1Publisher",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem1Publisher",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem1Publisher",
"visibleRule": "method = create && addOptionalItem1 != none"
},
{
"name": "optionalItem1Version",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem1Version",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem1Version",
"visibleRule": "method = create && addOptionalItem1 != none"
},
{
"name": "optionalItem1ProcessorArchitecture",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem1ProcessorArchitecture",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem1ProcessorArchitecture",
"visibleRule": "method = create && addOptionalItem1 != none"
},
{
"name": "optionalItem1URI",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem1URI",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem1URI",
"visibleRule": "method = create && addOptionalItem1 != none"
},
{
"name": "addOptionalItem2",
"type": "pickList",
"label": "ms-resource:loc.input.label.addOptionalItem2",
"defaultValue": "none",
"required": false,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.addOptionalItem2",
"visibleRule": "method = create && addOptionalItem1 != none",
"options": {
"none": "No Optional Package/Bundle",
"package": "Add Optional Package",
"bundle": "Add Optional Bundle"
}
},
{
"name": "optionalItem2Name",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem2Name",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem2Name",
"visibleRule": "method = create && addOptionalItem2 != none"
},
{
"name": "optionalItem2Publisher",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem2Publisher",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem2Publisher",
"visibleRule": "method = create && addOptionalItem2 != none"
},
{
"name": "optionalItem2Version",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem2Version",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem2Version",
"visibleRule": "method = create && addOptionalItem2 != none"
},
{
"name": "optionalItem2ProcessorArchitecture",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem2ProcessorArchitecture",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem2ProcessorArchitecture",
"visibleRule": "method = create && addOptionalItem2 != none"
},
{
"name": "optionalItem2URI",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem2URI",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem2URI",
"visibleRule": "method = create && addOptionalItem2 != none"
},
{
"name": "addOptionalItem3",
"type": "pickList",
"label": "ms-resource:loc.input.label.addOptionalItem3",
"defaultValue": "none",
"required": false,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.addOptionalItem3",
"visibleRule": "method = create && addOptionalItem2 != none",
"options": {
"none": "No Optional Package/Bundle",
"package": "Add Optional Package",
"bundle": "Add Optional Bundle"
}
},
{
"name": "optionalItem3Name",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem3Name",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem3Name",
"visibleRule": "method = create && addOptionalItem3 != none"
},
{
"name": "optionalItem3Publisher",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem3Publisher",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem3Publisher",
"visibleRule": "method = create && addOptionalItem3 != none"
},
{
"name": "optionalItem3Version",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem3Version",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem3Version",
"visibleRule": "method = create && addOptionalItem3 != none"
},
{
"name": "optionalItem3ProcessorArchitecture",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem3ProcessorArchitecture",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem3ProcessorArchitecture",
"visibleRule": "method = create && addOptionalItem3 != none"
},
{
"name": "optionalItem3URI",
"type": "string",
"label": "ms-resource:loc.input.label.optionalItem3URI",
"required": true,
"groupName": "optionalItems",
"helpMarkDown": "ms-resource:loc.input.help.optionalItem3URI",
"visibleRule": "method = create && addOptionalItem3 != none"
},
{
"name": "addDependency1",
"type": "pickList",
"label": "ms-resource:loc.input.label.addDependency1",
"defaultValue": "none",
"required": false,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.addDependency1",
"visibleRule": "method = create",
"options": {
"none": "No Dependency",
"package": "Add Package Dependency",
"bundle": "Add Bundle Dependency"
}
},
{
"name": "dependency1Name",
"type": "string",
"label": "ms-resource:loc.input.label.dependency1Name",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency1Name",
"visibleRule": "method = create && addDependency1 != none"
},
{
"name": "dependency1Publisher",
"type": "string",
"label": "ms-resource:loc.input.label.dependency1Publisher",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency1Publisher",
"visibleRule": "method = create && addDependency1 != none"
},
{
"name": "dependency1Version",
"type": "string",
"label": "ms-resource:loc.input.label.dependency1Version",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency1Version",
"visibleRule": "method = create && addDependency1 != none"
},
{
"name": "dependency1ProcessorArchitecture",
"type": "string",
"label": "ms-resource:loc.input.label.dependency1ProcessorArchitecture",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency1ProcessorArchitecture",
"visibleRule": "method = create && addDependency1 != none"
},
{
"name": "dependency1URI",
"type": "string",
"label": "ms-resource:loc.input.label.dependency1URI",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency1URI",
"visibleRule": "method = create && addDependency1 != none"
},
{
"name": "addDependency2",
"type": "pickList",
"label": "ms-resource:loc.input.label.addDependency2",
"defaultValue": "none",
"required": false,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.addDependency2",
"visibleRule": "method = create && addDependency1 != none",
"options": {
"none": "No Dependency",
"package": "Add Package Dependency",
"bundle": "Add Bundle Dependency"
}
},
{
"name": "dependency2Name",
"type": "string",
"label": "ms-resource:loc.input.label.dependency2Name",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency2Name",
"visibleRule": "method = create && addDependency2 != none"
},
{
"name": "dependency2Publisher",
"type": "string",
"label": "ms-resource:loc.input.label.dependency2Publisher",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency2Publisher",
"visibleRule": "method = create && addDependency2 != none"
},
{
"name": "dependency2Version",
"type": "string",
"label": "ms-resource:loc.input.label.dependency2Version",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency2Version",
"visibleRule": "method = create && addDependency2 != none"
},
{
"name": "dependency2ProcessorArchitecture",
"type": "string",
"label": "ms-resource:loc.input.label.dependency2ProcessorArchitecture",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency2ProcessorArchitecture",
"visibleRule": "method = create && addDependency2 != none"
},
{
"name": "dependency2URI",
"type": "string",
"label": "ms-resource:loc.input.label.dependency2URI",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency2URI",
"visibleRule": "method = create && addDependency2 != none"
},
{
"name": "addDependency3",
"type": "pickList",
"label": "ms-resource:loc.input.label.addDependency3",
"defaultValue": "none",
"required": false,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.addDependency3",
"visibleRule": "method = create && addDependency2 != none",
"options": {
"none": "No Dependency",
"package": "Add Package Dependency",
"bundle": "Add Bundle Dependency"
}
},
{
"name": "dependency3Name",
"type": "string",
"label": "ms-resource:loc.input.label.dependency3Name",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency3Name",
"visibleRule": "method = create && addDependency3 != none"
},
{
"name": "dependency3Publisher",
"type": "string",
"label": "ms-resource:loc.input.label.dependency3Publisher",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency3Publisher",
"visibleRule": "method = create && addDependency3 != none"
},
{
"name": "dependency3Version",
"type": "string",
"label": "ms-resource:loc.input.label.dependency3Version",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency3Version",
"visibleRule": "method = create && addDependency3 != none"
},
{
"name": "dependency3ProcessorArchitecture",
"type": "string",
"label": "ms-resource:loc.input.label.dependency3ProcessorArchitecture",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency3ProcessorArchitecture",
"visibleRule": "method = create && addDependency3 != none"
},
{
"name": "dependency3URI",
"type": "string",
"label": "ms-resource:loc.input.label.dependency3URI",
"required": true,
"groupName": "dependencies",
"helpMarkDown": "ms-resource:loc.input.help.dependency3URI",
"visibleRule": "method = create && addDependency3 != none"
}
]
}

Просмотреть файл

@ -0,0 +1,3 @@
{
"extends": "../tsconfig.json"
}

Просмотреть файл

@ -0,0 +1,72 @@
# Note: This script needs to be run with admin privileges.
param
(
# Must be a full path
[Parameter(Mandatory=$true)]
[string]$vhdxPath,
# Size in MB.
[Parameter(Mandatory=$true)]
[int]$vhdxSize,
[Parameter(Mandatory=$true)]
[string]$msixPackagePath,
[Parameter(Mandatory=$true)]
[string]$msixmgrPath
)
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:Encoding'] = 'utf8'
Remove-Item $vhdxPath -ErrorAction SilentlyContinue
# Create parent directory
New-Item -ItemType Directory -Path (Split-Path $vhdxPath) -ErrorAction SilentlyContinue
# Create the disk
# Note that the docs for creating a VHDX for app attach say to use
# New-VHD -SizeBytes $vhdxSize -Path $vhdxPath -Dynamic -Confirm:$false
# but New-VHD is not available on the build agents.
# Instead we use diskpart.
# diskpart is an interactive program. We pass it a script of what we want to do.
# We could also pass it through the standard input.
$scriptFile = Join-Path $env:TEMP 'create-vhdx.txt'
$diskpartCommand = "create vdisk file=`"$vhdxPath`" maximum=$vhdxSize"
Write-Host "diskpart command: $diskpartCommand"
$diskpartCommand | Out-File $scriptFile
try
{
Start-Process -Wait diskpart /s,$scriptFile
if (-not $?)
{
throw "Diskpart failed to create new virtual disk."
}
# Mount the disk
$vhdxObject = Mount-DiskImage $vhdxPath -Passthru
if (-not $?)
{
throw "Mounting virtual disk failed."
}
# Format the disk
$vhdxObject | Format-List
$disk = Initialize-Disk -Passthru -Number $vhdxObject.Number -PartitionStyle MBR
$partition = New-Partition -AssignDriveLetter -UseMaximumSize -DiskNumber $disk.Number
Format-Volume -FileSystem NTFS -Confirm:$false -DriveLetter $partition.DriveLetter -Force
# Create a directory to hold the app
$vhdxRoot = $partition.DriveLetter + ':\VHDXRoot'
New-Item -Path $vhdxRoot -ItemType Directory
# Unpack the app to the app into the distk
& $msixmgrPath -Unpack -packagePath $msixPackagePath -destination $vhdxRoot -applyacls
}
finally
{
# Remove-Item $scriptFile
Dismount-DiskImage $vhdxPath -ErrorAction SilentlyContinue
}

Просмотреть файл

@ -0,0 +1,12 @@
{
"loc.friendlyName": "Create package for MSIX app attach",
"loc.helpMarkDown": "",
"loc.description": "Create a VHD or VHDX package for MSIX app attach",
"loc.instanceNameFormat": "Create package for MSIX app attach",
"loc.input.label.package": "Package Path",
"loc.input.help.package": "Path to the package.",
"loc.input.label.vhdxOutputPath": "VHDX Output Path",
"loc.input.help.vhdxOutputPath": "The name of the VHDX file that will be created by the task.",
"loc.input.label.vhdxSize": "VHDX size (in MB)",
"loc.input.help.vhdxSize": "The maximum size in MBs of the VHDX."
}

Просмотреть файл

@ -0,0 +1,5 @@
# Set the task's inputs here to use when debugging
INPUT_PACKAGE=test\assets\existingPackage.msix
INPUT_VHDXOUTPUTPATH=debug\app.vhdx
INPUT_VHDXSIZE=100

Двоичные данные
tools/pipelines-tasks/MsixAppAttach/icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Просмотреть файл

@ -0,0 +1,40 @@
import path = require('path');
import tl = require('azure-pipelines-task-lib/task')
import { ToolRunner } from 'azure-pipelines-task-lib/toolrunner';
import helpers = require('common/helpers');
const MSIXMGR_PATH = path.join(__dirname, 'lib', 'msixmgr');
const GENERATE_VHDX_SCRIPT_PATH = path.join(__dirname, 'GenerateAppAttachVhdx.ps1')
/**
* Main function for the task.
*/
const run = async () =>
{
tl.setResourcePath(path.join(__dirname, 'task.json'));
// Read the task's inputs
const packagePath: string = helpers.getInputWithErrorCheck('package', 'No package path specified.');
const vhdxPath: string = helpers.getInputWithErrorCheck('vhdxOutputPath', 'A path is needed to create a new VHDX file, but none was given.');
const vhdxSize: string = helpers.getInputWithErrorCheck('vhdxSize', 'A size is needed to create a new VHDX file, but none was given.');
// The script requires the command path to be absolute.
const fullVhdxPath: string = path.resolve(vhdxPath);
const powershellRunner: ToolRunner = tl.tool('powershell');
powershellRunner.arg(GENERATE_VHDX_SCRIPT_PATH);
powershellRunner.arg(['-vhdxPath', fullVhdxPath]);
powershellRunner.arg(['-vhdxSize', vhdxSize]);
powershellRunner.arg(['-msixPackagePath', packagePath]);
powershellRunner.arg(['-msixmgrPath', MSIXMGR_PATH]);
// This script needs to be run as administrator.
await powershellRunner.exec();
}
run().catch(err =>
{
tl.setResult(tl.TaskResult.Failed, err.message);
})

Двоичные данные
tools/pipelines-tasks/MsixAppAttach/lib/applyacls.dll Normal file

Двоичный файл не отображается.

Двоичные данные
tools/pipelines-tasks/MsixAppAttach/lib/en-US/msixmgr.exe.mui Normal file

Двоичный файл не отображается.

Двоичные данные
tools/pipelines-tasks/MsixAppAttach/lib/msix.dll Normal file

Двоичный файл не отображается.

Двоичные данные
tools/pipelines-tasks/MsixAppAttach/lib/msixmgr.exe Normal file

Двоичный файл не отображается.

286
tools/pipelines-tasks/MsixAppAttach/package-lock.json сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,286 @@
{
"name": "msix-tasks-app-attach",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/node": {
"version": "14.6.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.4.tgz",
"integrity": "sha512-Wk7nG1JSaMfMpoMJDKUsWYugliB2Vy55pdjLpmLixeyMi7HizW2I/9QoxsPCkXl3dO+ZOVqPumKaDUv5zJu2uQ=="
},
"@types/xml2js": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.5.tgz",
"integrity": "sha512-yohU3zMn0fkhlape1nxXG2bLEGZRc1FeqF80RoHaYXJN7uibaauXfhzhOJr1Xh36sn+/tx21QAOf07b/xYVk1w==",
"requires": {
"@types/node": "*"
}
},
"adm-zip": {
"version": "0.4.16",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz",
"integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg=="
},
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"azure-devops-node-api": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-10.1.1.tgz",
"integrity": "sha512-P4Hyrh/+Nzc2KXQk73z72/GsenSWIH5o8uiyELqykJYs9TWTVCxVwghoR7lPeiY6QVoXkq2S2KtvAgi5fyjl9w==",
"requires": {
"tunnel": "0.0.6",
"typed-rest-client": "^1.7.3",
"underscore": "1.8.3"
}
},
"azure-pipelines-task-lib": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.10.0.tgz",
"integrity": "sha512-nmwf4ReXGfaBDMRO08/KSDOqbieJFljQSXd6bSFl28QsOKiGy5qz1O7pMnb9UqYfH5Fbro0zU4Q88hpO0XkFHg==",
"requires": {
"minimatch": "3.0.4",
"mockery": "^1.7.0",
"q": "^1.1.2",
"semver": "^5.1.0",
"shelljs": "^0.3.0",
"sync-request": "3.0.1",
"uuid": "^3.0.1"
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
},
"caseless": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
"integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c="
},
"common": {
"version": "file:../common/msix-tasks-helpers-1.0.0.tgz",
"integrity": "sha512-JqVtP3csFwsJmfeEfendFrjUE4R53/jVf1NIpB7at7SYM9dEXYvCibctQUztM58vqwJ7/Bh6Io/Gbd7mW677zQ==",
"requires": {
"@types/xml2js": "^0.4.5",
"adm-zip": "^0.4.16",
"azure-devops-node-api": "^10.1.1",
"azure-pipelines-task-lib": "^2.9.5",
"xml2js": "^0.4.23"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"http-basic": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/http-basic/-/http-basic-2.5.1.tgz",
"integrity": "sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=",
"requires": {
"caseless": "~0.11.0",
"concat-stream": "^1.4.6",
"http-response-object": "^1.0.0"
}
},
"http-response-object": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-1.1.0.tgz",
"integrity": "sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM="
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"mockery": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/mockery/-/mockery-1.7.0.tgz",
"integrity": "sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "~2.0.3"
}
},
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
},
"qs": {
"version": "6.9.4",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
"integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ=="
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"shelljs": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
"integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"sync-request": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/sync-request/-/sync-request-3.0.1.tgz",
"integrity": "sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=",
"requires": {
"concat-stream": "^1.4.7",
"http-response-object": "^1.0.1",
"then-request": "^2.0.1"
}
},
"then-request": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/then-request/-/then-request-2.2.0.tgz",
"integrity": "sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=",
"requires": {
"caseless": "~0.11.0",
"concat-stream": "^1.4.7",
"http-basic": "^2.5.1",
"http-response-object": "^1.1.0",
"promise": "^7.1.1",
"qs": "^6.1.0"
}
},
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"typed-rest-client": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.7.3.tgz",
"integrity": "sha512-CwTpx/TkRHGZoHkJhBcp4X8K3/WtlzSHVQR0OIFnt10j4tgy4ypgq/SrrgVpA1s6tAL49Q6J3R5C0Cgfh2ddqA==",
"requires": {
"qs": "^6.9.1",
"tunnel": "0.0.6",
"underscore": "1.8.3"
}
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"underscore": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
},
"xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"requires": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
}
},
"xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
}
}
}

Просмотреть файл

@ -0,0 +1,20 @@
{
"name": "msix-tasks-app-attach",
"version": "1.0.0",
"description": "Task to create VHDX files for MSIX app attach",
"repository": {
"type": "git",
"url": "git+github.com/microsoft/msix-ado-tasks-extension.git"
},
"scripts": {},
"author": "Microsoft Coporation",
"license": "MIT",
"dependencies": {
"azure-devops-node-api": "^10.1.1",
"azure-pipelines-task-lib": "^2.9.5",
"common": "file:../common/msix-tasks-helpers-1.0.0.tgz"
},
"devDependencies": {
"@types/node": "^14.0.5"
}
}

Просмотреть файл

@ -0,0 +1,49 @@
{
"$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
"id": "5acdf104-665e-4e06-a565-9f0a88e7de2b",
"name": "MsixAppAttach",
"friendlyName": "Create package for MSIX app attach",
"instanceNameFormat": "Create package for MSIX app attach",
"description": "Create a VHD or VHDX package for MSIX app attach",
"author": "Microsoft Corporation",
"category": "Package",
"helpMarkDown": "",
"execution": {
"Node10": {
"target": "index.js",
"platforms": [
"windows"
]
}
},
"version": {
"Major": 1,
"Minor": 0,
"Patch": 0
},
"minimumAgentVersion": "1.95.0",
"inputs": [
{
"name": "package",
"type": "string",
"label": "Package Path",
"required": true,
"helpMarkDown": "Path to the package."
},
{
"name": "vhdxOutputPath",
"type": "string",
"label": "VHDX Output Path",
"required": true,
"helpMarkDown": "The name of the VHDX file that will be created by the task."
},
{
"name": "vhdxSize",
"type": "string",
"label": "VHDX size (in MB)",
"defaultValue": "100",
"required": true,
"helpMarkDown": "The maximum size in MBs of the VHDX."
}
]
}

Просмотреть файл

@ -0,0 +1,49 @@
{
"$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
"id": "5acdf104-665e-4e06-a565-9f0a88e7de2b",
"name": "MsixAppAttach",
"friendlyName": "ms-resource:loc.friendlyName",
"instanceNameFormat": "ms-resource:loc.instanceNameFormat",
"description": "ms-resource:loc.description",
"author": "Microsoft Corporation",
"category": "Package",
"helpMarkDown": "ms-resource:loc.helpMarkDown",
"execution": {
"Node10": {
"target": "index.js",
"platforms": [
"windows"
]
}
},
"version": {
"Major": 1,
"Minor": 0,
"Patch": 0
},
"minimumAgentVersion": "1.95.0",
"inputs": [
{
"name": "package",
"type": "string",
"label": "ms-resource:loc.input.label.package",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.package"
},
{
"name": "vhdxOutputPath",
"type": "string",
"label": "ms-resource:loc.input.label.vhdxOutputPath",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.vhdxOutputPath"
},
{
"name": "vhdxSize",
"type": "string",
"label": "ms-resource:loc.input.label.vhdxSize",
"defaultValue": "100",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.vhdxSize"
}
]
}

Просмотреть файл

@ -0,0 +1,3 @@
{
"extends": "../tsconfig.json"
}

Просмотреть файл

@ -0,0 +1,9 @@
[CmdletBinding()]
param([string]$PreferredVersion, [string]$Architecture)
# The MSBuild helpers need the VSTS Task SDK.
# Import it before so it is available.
Import-Module $PSScriptRoot/ps_modules/VstsTaskSdk
Import-Module $PSScriptRoot/MSBuildHelpers/MSBuildHelpers
return Select-MSBuildPath -PreferredVersion $PreferredVersion -Architecture $Architecture 3>$null 6>$null

Просмотреть файл

@ -0,0 +1,47 @@
function Format-MSBuildArguments {
[CmdletBinding()]
param(
[string]$MSBuildArguments,
[string]$Platform,
[string]$Configuration,
[string]$VSVersion,
[switch]$MaximumCpuCount)
Trace-VstsEnteringInvocation $MyInvocation
try {
if ($Platform) {
Test-MSBuildParam $Platform 'Platform'
$MSBuildArguments = "$MSBuildArguments /p:platform=`"$Platform`""
}
if ($Configuration) {
Test-MSBuildParam $Configuration 'Configuration'
$MSBuildArguments = "$MSBuildArguments /p:configuration=`"$Configuration`""
}
if ($VSVersion) {
$MSBuildArguments = "$MSBuildArguments /p:VisualStudioVersion=`"$VSVersion`""
}
if ($MaximumCpuCount) {
$MSBuildArguments = "$MSBuildArguments /m"
}
$userAgent = Get-VstsTaskVariable -Name AZURE_HTTP_USER_AGENT
if ($userAgent) {
$MSBuildArguments = "$MSBuildArguments /p:_MSDeployUserAgent=`"$userAgent`""
}
$MSBuildArguments
} finally {
Trace-VstsLeavingInvocation $MyInvocation
}
}
function Test-MSBuildParam ([string]$msbuildParam, [string]$parameterName)
{
if ($msBuildParam -match '[<>*|:\/&%"#?]')
{
throw "The value of MSBuild parameter '$parameterName' ($msBuildParam) contains an invalid character. The value of $parameterName may not contain any of the following characters: < > * | : \ / & % `" # ?"
}
}

Просмотреть файл

@ -0,0 +1,176 @@
########################################
# Public functions.
########################################
function Invoke-BuildTools {
[CmdletBinding()]
param(
[switch]$NuGetRestore,
[string[]]$SolutionFiles,
[string]$MSBuildLocation, # TODO: Switch MSBuildLocation to mandatory. Both callers (MSBuild and VSBuild task) throw prior to reaching here if MSBuild cannot be resolved.
[string]$MSBuildArguments,
[switch]$Clean,
[switch]$NoTimelineLogger,
[switch]$CreateLogFile,
[string]$LogFileVerbosity)
Trace-VstsEnteringInvocation $MyInvocation
try {
foreach ($file in $SolutionFiles) {
if ($NuGetRestore) {
Invoke-NuGetRestore -File $file
}
$splat = @{ }
if ($LogFileVerbosity) {
$splat["LogFileVerbosity"] = $LogFileVerbosity
}
if ($Clean) {
if ($CreateLogFile) {
$splat["LogFile"] = "$file-clean.log"
}
Invoke-MSBuild -ProjectFile $file -Targets Clean -MSBuildPath $MSBuildLocation -AdditionalArguments $MSBuildArguments -NoTimelineLogger:$NoTimelineLogger @splat
}
# If we cleaned and passed /t targets, we don't need to run them again
if (!$Clean -or $MSBuildArguments -notmatch "[/-]t(arget)?:\S+") {
if ($CreateLogFile) {
$splat["LogFile"] = "$file.log"
}
Invoke-MSBuild -ProjectFile $file -MSBuildPath $MSBuildLocation -AdditionalArguments $MSBuildArguments -NoTimelineLogger:$NoTimelineLogger @splat
}
}
} finally {
Trace-VstsLeavingInvocation $MyInvocation
}
}
########################################
# Private functions.
########################################
function Invoke-MSBuild {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 1)]
[string]$ProjectFile,
[string]$Targets,
[string]$LogFile,
[string]$LogFileVerbosity,
[switch]$NoTimelineLogger,
[string]$MSBuildPath, # TODO: Switch MSBuildPath to mandatory. Both callers (MSBuild and VSBuild task) throw prior to reaching here if MSBuild cannot be resolved.
[string]$AdditionalArguments)
Trace-VstsEnteringInvocation $MyInvocation
try {
# Get the MSBuild path.
if (!$MSBuildPath) {
$MSBuildPath = Get-MSBuildPath # TODO: Delete this condition block. Both callers (MSBuild and VSBuild task) throw prior to reaching here if MSBuild cannot be resolved.
} else {
$MSBuildPath = [System.Environment]::ExpandEnvironmentVariables($MSBuildPath)
if ($MSBuildPath -notlike '*msbuild.exe') {
$MSBuildPath = [System.IO.Path]::Combine($MSBuildPath, 'msbuild.exe')
}
}
# Validate the path exists.
$null = Assert-VstsPath -LiteralPath $MSBuildPath -PathType Leaf
# Don't show the logo and do not allow node reuse so all child nodes are shut down once the master
# node has completed build orchestration.
$arguments = "`"$ProjectFile`" /nologo /nr:false"
# Add the targets if specified.
if ($Targets) {
$arguments = "$arguments /t:`"$Targets`""
}
# If a log file was specified then hook up the default file logger.
if ($LogFile) {
$arguments = "$arguments /fl /flp:`"logfile=$LogFile;verbosity=$LogFileVerbosity`""
}
# Start the detail timeline.
$detailId = ''
if (!$NoTimelineLogger) {
$detailId = [guid]::NewGuid()
$detailName = Get-VstsLocString -Key MSB_Build0 -ArgumentList ([System.IO.Path]::GetFileName($ProjectFile))
$detailStartTime = [datetime]::UtcNow.ToString('O')
Write-VstsLogDetail -Id $detailId -Type Process -Name $detailName -Progress 0 -StartTime $detailStartTime -State Initialized -AsOutput
}
# Store the solution folder so we can provide solution-relative paths (for now) for the project events.
$solutionDirectory = [System.IO.Path]::GetDirectoryName($ProjectFile)
# Hook up the custom logger.
$loggerAssembly = "$PSScriptRoot\Microsoft.TeamFoundation.DistributedTask.MSBuild.Logger.dll"
Assert-VstsPath -LiteralPath $loggerAssembly -PathType Leaf
$arguments = "$arguments /dl:CentralLogger,`"$loggerAssembly`";`"RootDetailId=$($detailId)|SolutionDir=$($solutionDirectory)`"*ForwardingLogger,`"$loggerAssembly`""
# Append additional arguments.
if ($AdditionalArguments) {
$arguments = "$arguments $AdditionalArguments"
}
$global:LASTEXITCODE = ''
try {
# Invoke MSBuild.
Invoke-VstsTool -FileName $MSBuildPath -Arguments $arguments -RequireExitCodeZero
if ($LASTEXITCODE -ne 0) {
Write-VstsSetResult -Result Failed -DoNotThrow
}
} finally {
# Complete the detail timeline.
if (!$NoTimelineLogger) {
if ($LASTEXITCODE -ne 0) {
$detailResult = 'Failed'
} else {
$detailResult = 'Succeeded'
}
$detailFinishTime = [datetime]::UtcNow.ToString('O')
Write-VstsLogDetail -Id $detailId -FinishTime $detailFinishTime -Progress 100 -State Completed -Result $detailResult -AsOutput
}
if ($LogFile) {
if (Test-Path -Path $LogFile) {
Write-Host "##vso[task.uploadfile]$LogFile"
} else {
Write-Verbose "Skipping upload of '$LogFile' since it does not exist."
}
}
}
} finally {
Trace-VstsLeavingInvocation $MyInvocation
}
}
function Invoke-NuGetRestore {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 1)]
[string]$File)
Trace-VstsEnteringInvocation $MyInvocation
try {
Write-Warning (Get-VstsLocString -Key MSB_RestoreNuGetPackagesDeprecated)
try {
$nuGetPath = Assert-VstsPath -LiteralPath "$(Get-VstsTaskVariable -Name Agent.HomeDirectory -Require)\externals\nuget\NuGet.exe" -PathType Leaf -PassThru
} catch {
# Temporary fallback logic for legacy Windows agent.
$nuGetPath = Assert-VstsPath -LiteralPath "$(Get-VstsTaskVariable -Name Agent.HomeDirectory -Require)\Agent\Worker\Tools\NuGet.exe" -PathType Leaf -PassThru
}
if ($env:NUGET_EXTENSIONS_PATH) {
Write-Host (Get-VstsLocString -Key MSB_DetectedNuGetExtensionsLoaderPath0 -ArgumentList $env:NUGET_EXTENSIONS_PATH)
}
$directory = [System.IO.Path]::GetDirectoryName($file)
Invoke-VstsTool -FileName $nuGetPath -Arguments "restore `"$file`" -NonInteractive" -WorkingDirectory $directory -RequireExitCodeZero
if ($LASTEXITCODE -ne 0) {
Write-VstsSetResult -Result Failed -DoNotThrow
}
} finally {
Trace-VstsLeavingInvocation $MyInvocation
}
}

Просмотреть файл

@ -0,0 +1,17 @@
[CmdletBinding()]
param()
Import-VstsLocStrings "$PSScriptRoot\module.json"
. $PSScriptRoot\ArgumentFunctions
. $PSScriptRoot\InvokeFunctions
. $PSScriptRoot\PathFunctions
Export-ModuleMember -Function @(
# Argument functions.
'Format-MSBuildArguments'
# Invoke functions.
'Invoke-BuildTools'
# Path functions.
'Get-MSBuildPath'
'Get-SolutionFiles'
'Get-VisualStudio'
'Select-MSBuildPath'
)

Просмотреть файл

@ -0,0 +1,309 @@
########################################
# Public functions.
########################################
$script:visualStudioCache = @{ }
########################################
# Public functions.
########################################
function Get-MSBuildPath {
[CmdletBinding()]
param(
[string]$Version,
[string]$Architecture)
Trace-VstsEnteringInvocation $MyInvocation
try {
# Only attempt to find Microsoft.Build.Utilities.Core.dll from a VS 15 Willow install
# when "15.0" or latest is specified. In 15.0, the method GetPathToBuildToolsFile(...)
# has regressed. When it is called for a version that is not found, the latest version
# found is returned instead. Same for "16.0"
[System.Reflection.Assembly]$msUtilities = $null
if (($Version -eq "16.0" -or !$Version) -and # !$Version indicates "latest"
($visualStudio16 = Get-VisualStudio 16) -and
$visualStudio16.installationPath) {
$msbuildUtilitiesPath = [System.IO.Path]::Combine($visualStudio16.installationPath, "MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll")
if (Test-Path -LiteralPath $msbuildUtilitiesPath -PathType Leaf) {
Write-Verbose "Loading $msbuildUtilitiesPath"
$msUtilities = [System.Reflection.Assembly]::LoadFrom($msbuildUtilitiesPath)
}
}
elseif (($Version -eq "15.0" -or !$Version) -and # !$Version indicates "latest"
($visualStudio15 = Get-VisualStudio 15) -and
$visualStudio15.installationPath) {
$msbuildUtilitiesPath = [System.IO.Path]::Combine($visualStudio15.installationPath, "MSBuild\15.0\Bin\Microsoft.Build.Utilities.Core.dll")
if (Test-Path -LiteralPath $msbuildUtilitiesPath -PathType Leaf) {
Write-Verbose "Loading $msbuildUtilitiesPath"
$msUtilities = [System.Reflection.Assembly]::LoadFrom($msbuildUtilitiesPath)
}
}
# Fallback to searching the GAC.
if (!$msUtilities) {
$msbuildUtilitiesAssemblies = @(
"Microsoft.Build.Utilities.Core, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"
"Microsoft.Build.Utilities.Core, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"
"Microsoft.Build.Utilities.v12.0, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"
"Microsoft.Build.Utilities.v4.0, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"
)
# Attempt to load a Microsoft build utilities DLL.
$index = 0
[System.Reflection.Assembly]$msUtilities = $null
while (!$msUtilities -and $index -lt $msbuildUtilitiesAssemblies.Length) {
Write-Verbose "Loading $($msbuildUtilitiesAssemblies[$index])"
try {
$msUtilities = [System.Reflection.Assembly]::Load((New-Object System.Reflection.AssemblyName($msbuildUtilitiesAssemblies[$index])))
} catch [System.IO.FileNotFoundException] {
Write-Verbose "Not found."
}
$index++
}
}
[string]$msBuildPath = $null
# Default to x86 architecture if not specified.
if (!$Architecture) {
$Architecture = "x86"
}
if ($msUtilities -ne $null) {
[type]$t = $msUtilities.GetType('Microsoft.Build.Utilities.ToolLocationHelper')
if ($t -ne $null) {
# Attempt to load the method info for GetPathToBuildToolsFile. This method
# is available in the 16.0, 15.0, 14.0, and 12.0 utilities DLL. It is not available
# in the 4.0 utilities DLL.
[System.Reflection.MethodInfo]$mi = $t.GetMethod(
"GetPathToBuildToolsFile",
[type[]]@( [string], [string], $msUtilities.GetType("Microsoft.Build.Utilities.DotNetFrameworkArchitecture") ))
if ($mi -ne $null -and $mi.GetParameters().Length -eq 3) {
$versions = "16.0", "15.0", "14.0", "12.0", "4.0"
if ($Version) {
$versions = @( $Version )
}
# Translate the architecture parameter into the corresponding value of the
# DotNetFrameworkArchitecture enum. Parameter three of the target method info
# takes this enum. Leverage parameter three to get to the enum's type info.
$param3 = $mi.GetParameters()[2]
$archValues = [System.Enum]::GetValues($param3.ParameterType)
[object]$archValue = $null
if ($Architecture -eq 'x86') {
$archValue = $archValues.GetValue(1) # DotNetFrameworkArchitecture.Bitness32
} elseif ($Architecture -eq 'x64') {
$archValue = $archValues.GetValue(2) # DotNetFrameworkArchitecture.Bitness64
} else {
$archValue = $archValues.GetValue(1) # DotNetFrameworkArchitecture.Bitness32
}
# Attempt to resolve the path for each version.
$versionIndex = 0
while (!$msBuildPath -and $versionIndex -lt $versions.Length) {
$msBuildPath = $mi.Invoke(
$null,
@( 'msbuild.exe' # string fileName
$versions[$versionIndex] # string toolsVersion
$archValue ))
$versionIndex++
}
} elseif (!$Version -or $Version -eq "4.0") {
# Attempt to load the method info GetPathToDotNetFrameworkFile. This method
# is available in the 4.0 utilities DLL.
$mi = $t.GetMethod(
"GetPathToDotNetFrameworkFile",
[type[]]@( [string], $msUtilities.GetType("Microsoft.Build.Utilities.TargetDotNetFrameworkVersion"), $msUtilities.GetType("Microsoft.Build.Utilities.DotNetFrameworkArchitecture") ))
if ($mi -ne $null -and $mi.GetParameters().Length -eq 3) {
# Parameter two of the target method info takes the TargetDotNetFrameworkVersion
# enum. Leverage parameter two to get the enum's type info.
$param2 = $mi.GetParameters()[1];
$frameworkVersionValues = [System.Enum]::GetValues($param2.ParameterType);
# Translate the architecture parameter into the corresponding value of the
# DotNetFrameworkArchitecture enum. Parameter three of the target method info
# takes this enum. Leverage parameter three to get to the enum's type info.
$param3 = $mi.GetParameters()[2];
$archValues = [System.Enum]::GetValues($param3.ParameterType);
[object]$archValue = $null
if ($Architecture -eq "x86") {
$archValue = $archValues.GetValue(1) # DotNetFrameworkArchitecture.Bitness32
} elseif ($Architecture -eq "x64") {
$archValue = $archValues.GetValue(2) # DotNetFrameworkArchitecture.Bitness64
} else {
$archValue = $archValues.GetValue(1) # DotNetFrameworkArchitecture.Bitness32
}
# Attempt to resolve the path.
$msBuildPath = $mi.Invoke(
$null,
@( "msbuild.exe" # string fileName
$frameworkVersionValues.GetValue($frameworkVersionValues.Length - 1) # enum TargetDotNetFrameworkVersion.VersionLatest
$archValue ))
}
}
}
}
if ($msBuildPath -and (Test-Path -LiteralPath $msBuildPath -PathType Leaf)) {
Write-Verbose "MSBuild: $msBuildPath"
$msBuildPath
}
} finally {
Trace-VstsLeavingInvocation $MyInvocation
}
}
function Get-SolutionFiles {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Solution)
Trace-VstsEnteringInvocation $MyInvocation
try {
if ($Solution.Contains("*") -or $Solution.Contains("?")) {
$solutionFiles = Find-VstsFiles -LegacyPattern $Solution
if (!$solutionFiles.Count) {
throw (Get-VstsLocString -Key MSB_SolutionNotFoundUsingSearchPattern0 -ArgumentList $Solution)
}
} else {
$solutionFiles = ,$Solution
}
$solutionFiles
} finally {
Trace-VstsLeavingInvocation $MyInvocation
}
}
function Get-VisualStudio {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[ValidateSet(15, 16)]
[int]$MajorVersion)
Trace-VstsEnteringInvocation $MyInvocation
try {
if (!$script:visualStudioCache.ContainsKey("$MajorVersion.0")) {
try {
# Query for the latest $MajorVersion.* version.
#
# Note, the capability is registered as VisualStudio_16.0, however the actual version
# may be something like 16.2.
Write-Verbose "Getting latest Visual Studio $MajorVersion setup instance."
$output = New-Object System.Text.StringBuilder
Invoke-VstsTool -FileName "$PSScriptRoot\vswhere.exe" -Arguments "-version [$MajorVersion.0,$($MajorVersion+1).0) -latest -format json" -RequireExitCodeZero 2>&1 |
ForEach-Object {
if ($_ -is [System.Management.Automation.ErrorRecord]) {
Write-Verbose "STDERR: $($_.Exception.Message)"
}
else {
Write-Verbose $_
$null = $output.AppendLine($_)
}
}
$script:visualStudioCache["$MajorVersion.0"] = (ConvertFrom-Json -InputObject $output.ToString()) |
Select-Object -First 1
if (!$script:visualStudioCache["$MajorVersion.0"]) {
# Query for the latest $MajorVersion.* BuildTools.
#
# Note, whereas VS 16.x version number is always 16.0.*, BuildTools does not follow the
# the same scheme. It appears to follow the 16.<UPDATE_NUMBER>.* versioning scheme.
Write-Verbose "Getting latest BuildTools 16 setup instance."
$output = New-Object System.Text.StringBuilder
Invoke-VstsTool -FileName "$PSScriptRoot\vswhere.exe" -Arguments "-version [$MajorVersion.0,$($MajorVersion+1).0) -products Microsoft.VisualStudio.Product.BuildTools -latest -format json" -RequireExitCodeZero 2>&1 |
ForEach-Object {
if ($_ -is [System.Management.Automation.ErrorRecord]) {
Write-Verbose "STDERR: $($_.Exception.Message)"
}
else {
Write-Verbose $_
$null = $output.AppendLine($_)
}
}
$script:visualStudioCache["$MajorVersion.0"] = (ConvertFrom-Json -InputObject $output.ToString()) |
Select-Object -First 1
}
} catch {
Write-Verbose ($_ | Out-String)
$script:visualStudioCache["$MajorVersion.0"] = $null
}
}
return $script:visualStudioCache["$MajorVersion.0"]
} finally {
Trace-VstsLeavingInvocation $MyInvocation
}
}
function Select-MSBuildPath {
[CmdletBinding()]
param(
[string]$Method,
[string]$Location,
[string]$PreferredVersion,
[string]$Architecture)
Trace-VstsEnteringInvocation $MyInvocation
try {
# Default the msbuildLocationMethod if not specified. The input msbuildLocationMethod
# was added to the definition after the input msbuildLocation.
if ("$Method".ToUpperInvariant() -ne 'LOCATION' -and "$Method".ToUpperInvariant() -ne 'VERSION') {
# Infer the msbuildLocationMethod based on the whether msbuildLocation is specified.
if ($Location) {
$Method = 'location'
} else {
$Method = 'version'
}
Write-Verbose "Defaulted MSBuild location method to: $Method"
}
if ("$Method".ToUpperInvariant() -eq 'LOCATION') {
# Return the location.
if ($Location) {
return $Location
}
# Fallback to version lookup.
Write-Verbose "Location not specified. Looking up by version instead."
}
$specificVersion = $PreferredVersion -and $PreferredVersion -ne 'latest'
$versions = "16.0", '15.0', '14.0', '12.0', '4.0' | Where-Object { $_ -ne $PreferredVersion }
# Look for a specific version of MSBuild.
if ($specificVersion) {
if (($path = Get-MSBuildPath -Version $PreferredVersion -Architecture $Architecture)) {
return $path
}
# Attempt to fallback.
Write-Verbose "Specified version '$PreferredVersion' and architecture '$Architecture' not found. Attempting to fallback."
}
# Look for the latest version of MSBuild.
foreach ($version in $versions) {
if (($path = Get-MSBuildPath -Version $version -Architecture $Architecture)) {
# Warn falling back.
if ($specificVersion) {
Write-Warning (Get-VstsLocString -Key 'MSB_UnableToFindMSBuildVersion0Architecture1FallbackVersion2' -ArgumentList $PreferredVersion, $Architecture, $version)
}
return $path
}
}
# Error. Not found.
if ($specificVersion) {
Write-Error (Get-VstsLocString -Key 'MSB_MSBuildNotFoundVersion0Architecture1' -ArgumentList $PreferredVersion, $Architecture)
} else {
Write-Error (Get-VstsLocString -Key 'MSB_MSBuildNotFound')
}
} finally {
Trace-VstsLeavingInvocation $MyInvocation
}
}

Просмотреть файл

@ -0,0 +1,11 @@
{
"loc.messages.MSB_Build0": "Build {0}",
"loc.messages.MSB_BuildToolNotFound": "MSBuild oder xbuild(Mono) wurde auf dem Mac-/Linux-Agent nicht gefunden.",
"loc.messages.MSB_DetectedNuGetExtensionsLoaderPath0": "Der Pfad des NuGet-Extensionladeprogramms wurde erkannt. Die Umgebungsvariable \"NUGET_EXTENSIONS_PATH\" ist auf \"{0}\" festgelegt.",
"loc.messages.MSB_MSBuild15NotFoundionArchitecture0": "MSBuild-Version \"15.0\" wurde bei der Architektur \"{0}\" nicht gefunden. Überprüfen Sie, ob der Architektureingabewert korrekt ist und ob Visual Studio 2017 installiert ist. MSBuild-Version \"15.0\" ist enthalten, wenn Visual Studio 2017 installiert ist.",
"loc.messages.MSB_MSBuildNotFound": "MSBuild wurde nicht gefunden. Versuchen Sie, den Speicherort von \"msbuild.exe\" anzugeben oder Visual Studio zu installieren. MSBuild ist enthalten, wenn Visual Studio installiert ist.",
"loc.messages.MSB_MSBuildNotFoundVersion0Architecture1": "MSBuild wurde für Version \"{0}\" und Architektur \"{1}\" nicht gefunden. Testen Sie eine andere Kombination aus Version und Architektur, geben Sie einen Speicherort an, oder installieren Sie die entsprechende Version von Visual Studio. MSBuild ist enthalten, wenn Visual Studio installiert ist.",
"loc.messages.MSB_RestoreNuGetPackagesDeprecated": "Die Option \"NuGet-Pakete wiederherstellen\" ist veraltet. Fügen Sie Ihrer Builddefinition zum Wiederherstellen von NuGet-Paketen im Build einen Task für den NuGet-Toolinstaller hinzu.",
"loc.messages.MSB_SolutionNotFoundUsingSearchPattern0": "Die Lösung wurde mithilfe des Suchmusters \"{0}\" nicht gefunden.",
"loc.messages.MSB_UnableToFindMSBuildVersion0Architecture1FallbackVersion2": "Die MSBuild-Version \"{0}\" für Architektur \"{1}\" wurde nicht gefunden. Die Version \"{2}\" wird verwendet."
}

Просмотреть файл

@ -0,0 +1,11 @@
{
"loc.messages.MSB_Build0": "Build {0}",
"loc.messages.MSB_BuildToolNotFound": "MSBuild or xbuild(Mono) were not found on the Mac/Linux agent.",
"loc.messages.MSB_DetectedNuGetExtensionsLoaderPath0": "Detected NuGet extensions loader path. Environment variable NUGET_EXTENSIONS_PATH is set to '{0}'.",
"loc.messages.MSB_MSBuild15NotFoundionArchitecture0": "MSBuild version '15.0' was not found for architecture '{0}'. Verify the architecture input value is correct and verify Visual Studio 2017 is installed. MSBuild version '15.0' is included when Visual Studio 2017 is installed.",
"loc.messages.MSB_MSBuildNotFound": "MSBuild was not found. Try specifying the location to msbuild.exe or install Visual Studio. MSBuild is included when Visual Studio is installed.",
"loc.messages.MSB_MSBuildNotFoundVersion0Architecture1": "MSBuild was not found for version '{0}' and architecture '{1}'. Try a different version/architecture combination, specify a location, or install the appropriate version of Visual Studio. MSBuild is included when Visual Studio is installed.",
"loc.messages.MSB_RestoreNuGetPackagesDeprecated": "The 'Restore NuGet Packages' option is deprecated. To restore NuGet packages in your build, add a NuGet Tool Installer task to your build definition.",
"loc.messages.MSB_SolutionNotFoundUsingSearchPattern0": "Solution not found using search pattern '{0}'.",
"loc.messages.MSB_UnableToFindMSBuildVersion0Architecture1FallbackVersion2": "Unable to find MSBuild version '{0}' for architecture '{1}'. Falling back to version '{2}'."
}

Просмотреть файл

@ -0,0 +1,11 @@
{
"loc.messages.MSB_Build0": "Compilación {0}",
"loc.messages.MSB_BuildToolNotFound": "No se encontró MSBuild o xbuild (Mono) en el agente para Mac o Linux.",
"loc.messages.MSB_DetectedNuGetExtensionsLoaderPath0": "Se detectó la ruta de acceso del cargador de extensiones de NuGet. La variable de entorno NUGET_EXTENSIONS_PATH está establecida en '{0}'.",
"loc.messages.MSB_MSBuild15NotFoundionArchitecture0": "No se encontró la versión de MSBuild \"15.0\" para la arquitectura \"{0}\". Compruebe que el valor de entrada de la arquitectura es correcto y compruebe que Visual Studio 2017 está instalado. La versión de MSBuild \"15.0\" se incluyó con la instalación de Visual Studio 2017.",
"loc.messages.MSB_MSBuildNotFound": "No se encontró MSBuild. Pruebe a especificar la ubicación de msbuild.exe o instale Visual Studio. MSBuild se incluyó con la instalación de Visual Studio.",
"loc.messages.MSB_MSBuildNotFoundVersion0Architecture1": "No se encontró MSBuild para la versión \"{0}\" y la arquitectura \"{1}\". Pruebe una combinación diferente de versión/arquitectura, especifique una ubicación o instale la versión adecuada de Visual Studio. MSBuild se incluyó con la instalación de Visual Studio.",
"loc.messages.MSB_RestoreNuGetPackagesDeprecated": "La opción \"Restaurar paquetes de NuGet\" está en desuso. Para restaurar paquetes de NuGet en la compilación, agregue una tarea del instalador de la herramienta NuGet a la definición de compilación.",
"loc.messages.MSB_SolutionNotFoundUsingSearchPattern0": "No se encontró la solución con el patrón de búsqueda '{0}'.",
"loc.messages.MSB_UnableToFindMSBuildVersion0Architecture1FallbackVersion2": "No se encuentra la versión de MSBuild \"{0}\" para la arquitectura \"{1}\". Revirtiendo a la versión \"{2}\"."
}

Просмотреть файл

@ -0,0 +1,11 @@
{
"loc.messages.MSB_Build0": "Build {0}",
"loc.messages.MSB_BuildToolNotFound": "MSBuild ou xbuild (Mono) sont introuvables sur l'agent Mac/Linux.",
"loc.messages.MSB_DetectedNuGetExtensionsLoaderPath0": "Le chemin du chargeur d'extensions NuGet a été détecté. La variable d'environnement NUGET_EXTENSIONS_PATH a la valeur '{0}'.",
"loc.messages.MSB_MSBuild15NotFoundionArchitecture0": "MSBuild version '15.0' est introuvable pour l'architecture '{0}'. Vérifiez que la valeur d'entrée de l'architecture est correcte et que Visual Studio 2017 est installé. MSBuild version '15.0' est inclus durant l'installation de Visual Studio 2017.",
"loc.messages.MSB_MSBuildNotFound": "MSBuild est introuvable. Essayez de spécifier l'emplacement à msbuild.exe, ou installez Visual Studio. MSBuild est inclus durant l'installation de Visual Studio.",
"loc.messages.MSB_MSBuildNotFoundVersion0Architecture1": "MSBuild est introuvable pour la version '{0}' et l'architecture '{1}'. Essayez une autre combinaison version/architecture, spécifiez un emplacement, ou installez la version appropriée de Visual Studio. MSBuild est inclus durant l'installation de Visual Studio.",
"loc.messages.MSB_RestoreNuGetPackagesDeprecated": "L'option Restaurer des packages NuGet est dépréciée. Pour restaurer des packages NuGet dans votre build, ajoutez une tâche Programme d'installation de l'outil NuGet à votre définition de build.",
"loc.messages.MSB_SolutionNotFoundUsingSearchPattern0": "Solution introuvable à l'aide du modèle de recherche '{0}'.",
"loc.messages.MSB_UnableToFindMSBuildVersion0Architecture1FallbackVersion2": "MSBuild version '{0}' est introuvable pour l'architecture '{1}'. Retour à la version '{2}'."
}

Просмотреть файл

@ -0,0 +1,11 @@
{
"loc.messages.MSB_Build0": "Compilazione {0}",
"loc.messages.MSB_BuildToolNotFound": "MSBuild o xbuild (Mono) non è stato trovato nell'agente Mac/Linux.",
"loc.messages.MSB_DetectedNuGetExtensionsLoaderPath0": "Il percorso del caricatore delle estensioni NuGet è stato rilevato. La variabile di ambiente NUGET_EXTENSIONS_PATH è impostata su '{0}'.",
"loc.messages.MSB_MSBuild15NotFoundionArchitecture0": "La versione '15.0' di MSBuild non è stata trovata per l'architettura '{0}'. Verificare che il valore di input dell'architettura sia corretto e che Visual Studio 2017 sia installato. La versione '15.0' di MSBuild è inclusa quando si installa Visual Studio 2017.",
"loc.messages.MSB_MSBuildNotFound": "MSBuild non è stato trovato. Provare a specificare il percorso di msbuild.exe o installare Visual Studio. MSBuild è incluso quando Visual Studio è installato.",
"loc.messages.MSB_MSBuildNotFoundVersion0Architecture1": "MSBuild non è stato trovato per la versione '{0}' e l'architettura '{1}'. Provare con una combinazione diversa di versione/architettura, specificare un percorso oppure installare la versione appropriata di Visual Studio. MSBuild è incluso quando si installa Visual Studio.",
"loc.messages.MSB_RestoreNuGetPackagesDeprecated": "L'opzione 'Ripristina pacchetti NuGet' è deprecata. Per ripristinare i pacchetti NuGet nella compilazione, aggiungere un'attività Programma di installazione strumento NuGet alla definizione di compilazione.",
"loc.messages.MSB_SolutionNotFoundUsingSearchPattern0": "Non sono state trovate soluzioni con il criterio di ricerca '{0}'.",
"loc.messages.MSB_UnableToFindMSBuildVersion0Architecture1FallbackVersion2": "La versione '{0}' di MSBuild non è stata trovata per l'architettura '{1}'. Verrà eseguito il fallback alla versione '{2}'."
}

Просмотреть файл

@ -0,0 +1,11 @@
{
"loc.messages.MSB_Build0": "ビルド: {0}",
"loc.messages.MSB_BuildToolNotFound": "MSBuild または xbuild(Mono) が Mac/Linux エージェント上に見つかりませんでした。",
"loc.messages.MSB_DetectedNuGetExtensionsLoaderPath0": "NuGet 拡張機能のローダー パスが検出されました。環境変数 NUGET_EXTENSIONS_PATH が '{0}' に設定されています。",
"loc.messages.MSB_MSBuild15NotFoundionArchitecture0": "MSBuild バージョン '15.0' がアーキテクチャ '{0}' にありません。アーキテクチャの入力値が正しいことを確認し、Visual Studio 2017 がインストールされていることを確認してください。MSBuild バージョン '15.0' は、Visual Studio 2017 のインストール時にインストールされます。",
"loc.messages.MSB_MSBuildNotFound": "MSBuild が見つかりませんでした。msbuild.exe の場所を指定するか、Visual Studio をインストールしてください。MSBuild は Visual Studio のインストール時にインストールされます。",
"loc.messages.MSB_MSBuildNotFoundVersion0Architecture1": "バージョン '{0}' およびアーキテクチャ '{1}' の MSBuild が見つかりませんでした。バージョン/アーキテクチャの別の組み合わせを試し、場所を指定し、適切なバージョンの Visual Studio をインストールしてください。MSBuild は Visual Studio のインストール時にインストールされます。",
"loc.messages.MSB_RestoreNuGetPackagesDeprecated": "'NuGet パッケージの復元' オプションは非推奨になりました。ビルド内の NuGet パッケージを復元するには、NuGet Tool インストーラーのタスクをビルド定義に追加します。",
"loc.messages.MSB_SolutionNotFoundUsingSearchPattern0": "検索パターン '{0}' を使ってソリューションが見つかりませんでした。",
"loc.messages.MSB_UnableToFindMSBuildVersion0Architecture1FallbackVersion2": "アーキテクチャ '{1}' の MSBuild バージョン '{0}' が見つかりません。バージョン '{2}' にフォールバックします。"
}

Просмотреть файл

@ -0,0 +1,11 @@
{
"loc.messages.MSB_Build0": "빌드 {0}",
"loc.messages.MSB_BuildToolNotFound": "Mac/Linux 에이전트에서 MSBuild 또는 xbuild(Mono)를 찾을 수 없습니다.",
"loc.messages.MSB_DetectedNuGetExtensionsLoaderPath0": "NuGet 확장 로드 경로가 검색되었습니다. 환경 변수 NUGET_EXTENSIONS_PATH는 '{0}'(으)로 설정되어 있습니다.",
"loc.messages.MSB_MSBuild15NotFoundionArchitecture0": "아키텍처 '{0}'에 대해 MSBuild 버전 '15.0'을 찾을 수 없습니다. 아키텍처 입력 값이 올바른지 확인하고 Visual Studio 2017이 설치되어 있는지 확인하세요. Visual Studio 2017을 설치할 때 MSBuild 버전 '15.0'이 포함됩니다.",
"loc.messages.MSB_MSBuildNotFound": "MSBuild를 찾을 수 없습니다. msbuild.exe에 대한 위치를 지정하거나 Visual Studio를 설치하세요. Visual Studio를 설치할 때 MSBuild가 포함됩니다.",
"loc.messages.MSB_MSBuildNotFoundVersion0Architecture1": "버전 '{0}' 및 아키텍처 '{1}'에 대해 MSBuild를 찾을 수 없습니다. 다른 버전/아키텍처 조합을 시도해 보거나, 위치를 지정하거나, 적합한 버전의 Visual Studio를 설치해 보세요. Visual Studio를 설치할 때 MSBuild가 포함됩니다.",
"loc.messages.MSB_RestoreNuGetPackagesDeprecated": "'NuGet 패키지 복원' 옵션은 사용되지 않습니다. 빌드에서 NuGet 패키지를 복원하려면 빌드 정의에 NuGet 도구 설치 관리자 작업을 추가하세요.",
"loc.messages.MSB_SolutionNotFoundUsingSearchPattern0": "검색 패턴 '{0}'을(를) 사용하여 솔루션을 찾을 수 없습니다.",
"loc.messages.MSB_UnableToFindMSBuildVersion0Architecture1FallbackVersion2": "아키텍처 '{1}'에 대해 MSBuild 버전 '{0}'을(를) 찾을 수 없습니다. '{2}' 버전을 대신 사용합니다."
}

Просмотреть файл

@ -0,0 +1,11 @@
{
"loc.messages.MSB_Build0": "Сборка {0}",
"loc.messages.MSB_BuildToolNotFound": "В агенте Mac/Linux не удалось найти MSBuild или xbuild (Mono).",
"loc.messages.MSB_DetectedNuGetExtensionsLoaderPath0": "Обнаружен путь к загрузчику расширений NuGet. Для переменной среды NUGET_EXTENSIONS_PATH задано значение \"{0}\".",
"loc.messages.MSB_MSBuild15NotFoundionArchitecture0": "Не найдено средство MSBuild 15.0 для архитектуры \"{0}\". Проверьте правильность входного значения архитектуры и убедитесь, что среда Visual Studio 2017 установлена. Средство MSBuild версии 15.0 включено в установку Visual Studio 2017.",
"loc.messages.MSB_MSBuildNotFound": "Не найдено средство MSBuild. Укажите расположение msbuild.exe или установите Visual Studio. Средство MSBuild включено в установку Visual Studio.",
"loc.messages.MSB_MSBuildNotFoundVersion0Architecture1": "Не найдено средство MSBuild \"{0}\" для архитектуры \"{1}\". Попробуйте использовать другую комбинацию версии и архитектуры, укажите расположение или установите соответствующую версию Visual Studio. Средство MSBuild включено в установку Visual Studio.",
"loc.messages.MSB_RestoreNuGetPackagesDeprecated": "Параметр \"Восстановить пакеты NuGet\" является устаревшим. Чтобы восстановить пакеты NuGet в сборке, добавьте задание установщика средства NuGet в определение сборки.",
"loc.messages.MSB_SolutionNotFoundUsingSearchPattern0": "Не удалось найти решение по шаблону поиска \"{0}\".",
"loc.messages.MSB_UnableToFindMSBuildVersion0Architecture1FallbackVersion2": "Не удалось найти MSBuild версии \"{0}\" для архитектуры \"{1}\". Выполняется откат к версии {2}."
}

Просмотреть файл

@ -0,0 +1,11 @@
{
"loc.messages.MSB_Build0": "生成 {0}",
"loc.messages.MSB_BuildToolNotFound": "Mac/Linux 代理上找不到 MSBuild 或 xbuild(Mono)。",
"loc.messages.MSB_DetectedNuGetExtensionsLoaderPath0": "已检测到 NuGet 扩展加载程序路径。将环境变量 NUGET_EXTENSIONS_PATH 设置为“{0}”。",
"loc.messages.MSB_MSBuild15NotFoundionArchitecture0": "找不到适用于体系结构“{0}”的 MSBuild 版本 \"15.0\"。请验证体系结构输入值正确,且已安装 Visual Studio 2017。安装 Visual Studio 2017 时 MSBuild 版本 \"15.0\" 也包括在内。",
"loc.messages.MSB_MSBuildNotFound": "找不到 MSBuild。尝试指定 msbuild.exe 的位置或安装 Visual Studio。安装 Visual Studio 时 MSBuild 也包括在内。",
"loc.messages.MSB_MSBuildNotFoundVersion0Architecture1": "找不到适用于体系结构“{1}”的 MSBuild 版本“{0}”。请尝试其他版本/体系结构组合,指定一个位置或安装合适版本的 Visual Studio。安装 Visual Studio 时 MSBuild 也包括在内。",
"loc.messages.MSB_RestoreNuGetPackagesDeprecated": "“还原 NuGet 包”选项已弃用。若要在生成中还原 NuGet 包,请将 NuGet 工具安装程序任务添加到生成定义中。",
"loc.messages.MSB_SolutionNotFoundUsingSearchPattern0": "使用搜索模式“{0}”找不到解决方案。",
"loc.messages.MSB_UnableToFindMSBuildVersion0Architecture1FallbackVersion2": "找不到适用于体系结构“{1}”的 MSBuild 版本“{0}”。正在回退到版本“{2}”。"
}

Просмотреть файл

@ -0,0 +1,11 @@
{
"loc.messages.MSB_Build0": "組建 {0}",
"loc.messages.MSB_BuildToolNotFound": "在 Mac/Linux 代理程式上找不到 MSBuild 或 xbuild (Mono)。",
"loc.messages.MSB_DetectedNuGetExtensionsLoaderPath0": "偵測到 NuGet 擴充功能載入器路徑。環境變數 NUGET_EXTENSIONS_PATH 設定為 '{0}'。",
"loc.messages.MSB_MSBuild15NotFoundionArchitecture0": "架構 '{0}' 中找不到 MSBuild 版本 '15.0'。請確認架構輸入值是否正確,且確認是否已安裝 Visual Studio 2017。已安裝 Visual Studio 2017 時會包含 MSBuild 版本 '15.0'。",
"loc.messages.MSB_MSBuildNotFound": "找不到 MSBuild。請嘗試指定 msbuild.exe 的位置或安裝 Visual Studio。已安裝 Visual Studio 時會包含 MSBuild。",
"loc.messages.MSB_MSBuildNotFoundVersion0Architecture1": "版本 '{0}' 與架構 '{1}' 中找不到 MSBuild。請嘗試其他版本/架構組合的、指定位置,或安裝正確的 Visual Studio 版本。已安裝 Visual Studio 時會包含 MSBuild。",
"loc.messages.MSB_RestoreNuGetPackagesDeprecated": "[還原 NuGet 套件] 選項即將淘汰。若要還原組件中的 NuGet 套件,請在組建定義中新增 NuGet 工具安裝程式工作。",
"loc.messages.MSB_SolutionNotFoundUsingSearchPattern0": "使用搜尋模式 '{0}' 找不到解決方案。",
"loc.messages.MSB_UnableToFindMSBuildVersion0Architecture1FallbackVersion2": "找不到架構 '{1}' 的 MSBuild 版本 '{0}'。切換回版本 '{2}'。"
}

Просмотреть файл

@ -0,0 +1,14 @@
{
"externals": {
"archivePackages": [
{
"url": "https://vstsagenttools.blob.core.windows.net/tools/msbuildlogger/3/msbuildlogger.zip",
"dest": "./"
},
{
"url": "https://vstsagenttools.blob.core.windows.net/tools/vswhere/1_0_62/vswhere.zip",
"dest": "./"
}
]
}
}

Просмотреть файл

@ -0,0 +1,13 @@
{
"messages": {
"MSB_Build0" : "Build {0}",
"MSB_BuildToolNotFound": "MSBuild or xbuild(Mono) were not found on the Mac/Linux agent.",
"MSB_DetectedNuGetExtensionsLoaderPath0": "Detected NuGet extensions loader path. Environment variable NUGET_EXTENSIONS_PATH is set to '{0}'.",
"MSB_MSBuild15NotFoundionArchitecture0": "MSBuild version '15.0' was not found for architecture '{0}'. Verify the architecture input value is correct and verify Visual Studio 2017 is installed. MSBuild version '15.0' is included when Visual Studio 2017 is installed.",
"MSB_MSBuildNotFound": "MSBuild was not found. Try specifying the location to msbuild.exe or install Visual Studio. MSBuild is included when Visual Studio is installed.",
"MSB_MSBuildNotFoundVersion0Architecture1": "MSBuild was not found for version '{0}' and architecture '{1}'. Try a different version/architecture combination, specify a location, or install the appropriate version of Visual Studio. MSBuild is included when Visual Studio is installed.",
"MSB_RestoreNuGetPackagesDeprecated": "The 'Restore NuGet Packages' option is deprecated. To restore NuGet packages in your build, add a NuGet Tool Installer task to your build definition.",
"MSB_SolutionNotFoundUsingSearchPattern0": "Solution not found using search pattern '{0}'.",
"MSB_UnableToFindMSBuildVersion0Architecture1FallbackVersion2": "Unable to find MSBuild version '{0}' for architecture '{1}'. Falling back to version '{2}'."
}
}

Просмотреть файл

@ -0,0 +1,49 @@
import tl = require('azure-pipelines-task-lib/task');
/**
* Finds the tool path for msbuild/xbuild based on specified msbuild version on Mac or Linux agent
* @param version
*/
export async function getMSBuildPath(version: string) {
let toolPath: string | undefined;
if (version === '15.0' || version === 'latest') {
let msbuildPath: string = tl.which('msbuild', false);
if (msbuildPath) {
// msbuild found on the agent, check version
let msbuildVersion: number | undefined;
let msbuildVersionCheckTool = tl.tool(msbuildPath);
msbuildVersionCheckTool.arg(['/version', '/nologo']);
msbuildVersionCheckTool.on('stdout', function (data) {
if (data) {
let intData = parseInt(data.toString().trim());
if (intData && !isNaN(intData)) {
msbuildVersion = intData;
}
}
})
await msbuildVersionCheckTool.exec();
if (msbuildVersion) {
// found msbuild version on the agent, check if it matches requirements
if (msbuildVersion >= 15) {
toolPath = msbuildPath;
}
}
}
}
if (!toolPath) {
// either user selected old version of msbuild or we didn't find matching msbuild version on the agent
// fallback to xbuild
toolPath = tl.which('xbuild', false);
if (!toolPath) {
// failed to find a version of msbuild / xbuild on the agent
throw tl.loc('MSB_BuildToolNotFound');
}
}
return toolPath;
}

73
tools/pipelines-tasks/MsixPackaging/MSBuildHelpers/package-lock.json сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,73 @@
{
"name": "msbuildhelpers",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"azure-pipelines-task-lib": {
"version": "2.9.3",
"resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.9.3.tgz",
"integrity": "sha512-SPWKSfgmjyBDVIMzXnnPH0Gv7YXZ+AQ3SyIhNNALAmQpOltqJhgslvzrOClR5rKuoOyJlG0AWZILbZIXCkztAA==",
"requires": {
"minimatch": "3.0.4",
"mockery": "^1.7.0",
"q": "^1.1.2",
"semver": "^5.1.0",
"shelljs": "^0.3.0",
"uuid": "^3.0.1"
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
"integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"mockery": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/mockery/-/mockery-1.7.0.tgz",
"integrity": "sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8="
},
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
},
"semver": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
},
"shelljs": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
"integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E="
},
"uuid": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz",
"integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA=="
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
{
"name": "msbuildhelpers",
"version": "1.0.0",
"description": "Azure Pipelines tasks MSBuild helpers",
"main": "msbuildhelpers.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/Microsoft/azure-pipelines-tasks.git"
},
"author": "Microsoft Corporation",
"license": "MIT",
"bugs": {
"url": "https://github.com/Microsoft/azure-pipelines-tasks/issues"
},
"homepage": "https://github.com/Microsoft/azure-pipelines-tasks#readme",
"dependencies": {
"azure-pipelines-task-lib": "^2.9.3"
}
}

Просмотреть файл

@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"declaration": true,
"noImplicitAny": false,
"sourceMap": false
},
"exclude": [
"node_modules"
]
}

Просмотреть файл

@ -0,0 +1,8 @@
{
"name": "msbuildhelpers",
"dependencies": {},
"globalDependencies": {
"node": "registry:dt/node#6.0.0+20160915134512",
"q": "registry:dt/q#0.0.0+20160613154756"
}
}

Двоичные данные
tools/pipelines-tasks/MsixPackaging/MSBuildHelpers/vswhere.exe Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,46 @@
{
"loc.friendlyName": "MSIX build and package",
"loc.helpMarkDown": "",
"loc.description": "Build and package Windows apps using the MSIX package format",
"loc.instanceNameFormat": "MSIX build and package",
"loc.group.displayName.msbuild": "Advanced Options for MSBuild",
"loc.input.label.outputPath": "Output Path",
"loc.input.help.outputPath": "Path of the generated package or bundle.",
"loc.input.label.buildSolution": "Build Solution with MSBuild",
"loc.input.help.buildSolution": "Invoke MSBuild and build the solution from scratch. If this is selected, you must provide a path to the solution file to build and select the target platforms to build.",
"loc.input.label.inputDirectory": "Input Directory",
"loc.input.help.inputDirectory": "Relative path from the repo root to the directory with the files to be packaged.",
"loc.input.label.solution": "Project to Build",
"loc.input.help.solution": "Relative path from repo root of the project or solution to build. Wildcards can be used.",
"loc.input.label.clean": "Clean Before Building",
"loc.input.help.clean": "Run a clean build (/t:clean) prior to the build.",
"loc.input.label.generateBundle": "Generate MSIX Bundle",
"loc.input.help.generateBundle": "Generate an MSIX bundle.",
"loc.input.label.buildConfiguration": "Configuration",
"loc.input.help.buildConfiguration": "The configuration to build the solution with. Only one configuration is supported at a time.",
"loc.input.label.buildPlatform": "Platform",
"loc.input.help.buildPlatform": "Specify the platform you want to build such as Win32, x86, x64 or any cpu.",
"loc.input.label.buildForX86": "Build for x86",
"loc.input.help.buildForX86": "Build the solution for the x86 platform.",
"loc.input.label.buildForX64": "Build for x64",
"loc.input.help.buildForX64": "Build the solution for the x64 platform.",
"loc.input.label.buildForArm": "Build for ARM",
"loc.input.help.buildForArm": "Build the solution for the ARM platform.",
"loc.input.label.buildForAnyCpu": "Build for Any CPU",
"loc.input.help.buildForAnyCpu": "Build the solution for the Any CPU platform.",
"loc.input.label.updateAppVersion": "Update App Version in Manifest",
"loc.input.help.updateAppVersion": "Update the app version from the one in the manifest.",
"loc.input.label.manifestFile": "Manifest File to Update Version",
"loc.input.help.manifestFile": "Path to the manifest file. This is only used to update the app version.",
"loc.input.label.appVersion": "App Version",
"loc.input.help.appVersion": "Version number to set for the app.",
"loc.input.label.appPackageDistributionMode": "Application Package Distribution Mode",
"loc.input.help.appPackageDistributionMode": "Whether to generate the .msixupload file for Store upload, the .msix/.msixbundle for non-Store apps, or both.",
"loc.input.label.msbuildLocationMethod": "MSBuild",
"loc.input.label.msbuildVersion": "MSBuild Version",
"loc.input.help.msbuildVersion": "If the preferred version cannot be found, the latest version found will be used instead.",
"loc.input.label.msbuildArchitecture": "MSBuild Architecture",
"loc.input.help.msbuildArchitecture": "Optionally supply the architecture (x86, x64) of MSBuild to run.",
"loc.input.label.msbuildLocation": "Path to MSBuild",
"loc.input.help.msbuildLocation": "Optionally supply the path to MSBuild."
}

Просмотреть файл

@ -0,0 +1,28 @@
# Set the task's inputs here to use when debugging
# This is to allow loading the VSTS SDK for the MSBuild helpers
SYSTEM_CULTURE="en-US"
INPUT_BUILDSOLUTION=false
INPUT_CLEAN=true
INPUT_OUTPUTPATH=debug\App.msix
INPUT_INPUTDIRECTORY=test\assets\PrebuiltBinaries\
INPUT_SOLUTION=test\assets\HelloWorldUWPApp\HelloWorldApp.sln
INPUT_BUILDCONFIGURATION=debug
INPUT_BUILDPLATFORM=x86
INPUT_BUILDFORX86=true
INPUT_BUILDFORX64=true
INPUT_GENERATEBUNDLE=false
INPUT_MSBUILDLOCATIONMETHOD=version
INPUT_MSBUILDVERSION=latest
INPUT_MSBUILDARCHITECTURE=x86
INPUT_MSBUILDLOCATION=C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Current\Bin\msbuild.exe
INPUT_UPDATEAPPVERSION=true
INPUT_MANIFESTFILE=test\assets\HelloWorldUWPApp\Package.appxmanifest
INPUT_APPVERSION=1.2.3.4

Двоичные данные
tools/pipelines-tasks/MsixPackaging/icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Просмотреть файл

@ -0,0 +1,161 @@
import path = require('path');
import tl = require('azure-pipelines-task-lib/task')
import { ToolRunner } from 'azure-pipelines-task-lib/toolrunner';
import helpers = require('common/helpers');
import msbuild = require('./msbuild');
/**
* Reads the inputs needed for updating the app version in the manifest,
* then edits it with the new version.
*/
const updateAppVersionInManifest = async () =>
{
// read the input
const manifestFile: string = helpers.getInputWithErrorCheck('manifestFile', 'To update the version of the app, the path to the manifest file is required to get the current version, but none was given.');
// get the new version
let newVersion: string = helpers.getInputWithErrorCheck('appVersion', 'To manually update the version of the app, a new version is required but none was given.');
const parsedManifest: any = await helpers.parseXml(manifestFile);
parsedManifest.Package.Identity[0].$.Version = newVersion;
helpers.writeXml(parsedManifest, manifestFile);
}
/**
* Gets the list of platforms to build from the input.
*/
const getPlatformsToBuild = (): string[] =>
{
const allPlatforms: { [platform: string]: boolean } =
{
'x86': tl.getBoolInput('buildForX86'),
'x64': tl.getBoolInput('buildForX64'),
'ARM': tl.getBoolInput('buildForArm'),
'Any CPU': tl.getBoolInput('buildForAnyCpu')
};
const selectedPlatforms: string[] = [];
Object.keys(allPlatforms).forEach(key =>
{
if (allPlatforms[key])
{
selectedPlatforms.push(key);
}
});
return selectedPlatforms;
}
/**
* Reads the inputs for MSBuild and calls it to build the solution and
* create the packages and bundle.
* @param outputPath Save location for the produced package or bundle.
* @param createBundle Whether we are creating a bundle or a package.
*/
const setUpAndRunMSBuild = async (outputPath: string, createBundle: boolean) =>
{
const msbuildCommonParameters: msbuild.MSBuildCommonParameters = msbuild.readMSBuildInputs();
if (createBundle)
{
const platformsToBuild: string[] = getPlatformsToBuild();
if (!platformsToBuild.length)
{
throw Error('No platform was specified to be built.');
}
await msbuild.runMSBuild(createBundle, outputPath, platformsToBuild, msbuildCommonParameters);
}
else
{
const platform: string = helpers.getInputWithErrorCheck('buildPlatform', 'Platform to build is required.');
await msbuild.runMSBuild(createBundle, outputPath, [platform], msbuildCommonParameters);
}
}
/**
* Package prebuilt binaries.
* @param outputPath Save location for the generated package or bundle.
* @param createBundle Whether to produce a bundle or a package.
*/
const packageBuiltBinaries = async (outputPath: string, createBundle: boolean, inputDirectory: string) =>
{
// The makemsix tool has a quirk where if the path ends with a slash, the tool
// will fail, so we detect this and work around this problem by removing the
// trailing slash if present
const lastChar: string = inputDirectory[inputDirectory.length - 1];
if (lastChar === '\\' || lastChar === '/')
{
console.log("inputDirectory ends with \\ trimming it...");
inputDirectory = inputDirectory.slice(0, -1);
}
if (!createBundle)
{
// TODO: Replace makeappx by makemsix to make it cross-platform
const makeAppxPackRunner: ToolRunner = tl.tool(helpers.MAKEAPPX_PATH);
makeAppxPackRunner.arg('pack');
makeAppxPackRunner.arg(['/o', '/v']);
makeAppxPackRunner.arg(['/d', inputDirectory]);
makeAppxPackRunner.arg(['/p', outputPath]);
await makeAppxPackRunner.exec();
}
else
{
const makeAppxBundleRunner: ToolRunner = tl.tool(helpers.MAKEAPPX_PATH);
makeAppxBundleRunner.arg('bundle');
makeAppxBundleRunner.arg(['/o', '/v']);
makeAppxBundleRunner.arg(['/d', inputDirectory]);
makeAppxBundleRunner.arg(['/p', outputPath]);
await makeAppxBundleRunner.exec();
}
}
/**
* Main function for the task.
*/
const run = async () =>
{
tl.setResourcePath(path.join(__dirname, 'task.json'));
// detect if the user will provide pre-built binaries or use MSBuild
const buildSolution: boolean = tl.getBoolInput('buildSolution', /* required: */ true);
let inputDirectory: string | undefined;
if (!buildSolution)
{
inputDirectory = helpers.getInputWithErrorCheck('inputDirectory', 'To package pre-built binaries, a path to the directory containing valid binaries is required, but none was given.');
}
// read output path for the package or bundle.
// resolve it to a full path to ensure it is the same in every place.
// e.g. MSBuild seems to use the path relative to the solution dir in some cases.
const outputPath: string = path.resolve(helpers.getInputWithErrorCheck('outputPath', 'An output path is required to save the package, but none was given.'));
// whether to bundle or not is independent of whether or not to build from scratch
// if the user gives the bundle option, check that they gave a path to save the output bundle.
const generateBundle: boolean = tl.getBoolInput('generateBundle');
// update the app version in the manifest
const updateAppVersion: boolean = tl.getBoolInput('updateAppVersion');
if (updateAppVersion)
{
await updateAppVersionInManifest();
}
// create the packages and bundle
if (buildSolution)
{
await setUpAndRunMSBuild(outputPath, generateBundle);
}
else
{
await packageBuiltBinaries(outputPath, generateBundle, inputDirectory!);
}
}
run().catch(err =>
{
tl.setResult(tl.TaskResult.Failed, err.message);
})

Просмотреть файл

@ -0,0 +1,163 @@
import os = require('os');
import path = require('path');
import tl = require('azure-pipelines-task-lib/task');
import { ToolRunner } from 'azure-pipelines-task-lib/toolrunner';
import helpers = require('common/helpers');
import msbuildHelpers = require('./MSBuildHelpers/msbuildhelpers');
const MSBUILD_PATH_HELPER_SCRIPT = path.join(__dirname, 'GetMSBuildPath.ps1');
export interface MSBuildCommonParameters
{
solution: string;
configuration: string;
msbuildArguments: string;
appxPackageBuildMode: string,
clean: boolean;
msbuildLocationMethod: string;
msbuildLocation?: string;
msbuildVersion?: string;
msbuildArchitecture?: string;
}
/**
* Reads the task's inputs related to MSBuild that are common to creating packages and bundle.
*/
export const readMSBuildInputs = (): MSBuildCommonParameters =>
{
const solution: string = helpers.getInputWithErrorCheck('solution', 'A path to a solution is required.');
const configuration: string = helpers.getInputWithErrorCheck('buildConfiguration', 'Build configuration is required.');
const msbuildArguments: string = '/p:AppxPackageSigningEnabled=false';
const clean: boolean = tl.getBoolInput('clean');
const appxPackageBuildMode: string = tl.getInput('appPackageDistributionMode') ?? 'SideloadOnly'
const msbuildLocationMethod: string = helpers.getInputWithErrorCheck('msBuildLocationMethod', 'Method to locate MSBuild is required.');
let msbuildVersion: string | undefined;
let msbuildArchitecture: string | undefined;
if (msbuildLocationMethod === 'version')
{
msbuildVersion = helpers.getInputWithErrorCheck('msbuildVersion', 'Version of MSBuild to use is required.');
msbuildArchitecture = helpers.getInputWithErrorCheck('msbuildArchitecture', 'Build architecture of MSBuild to use is required.');
}
let msbuildLocation: string | undefined;
if (msbuildLocationMethod === 'location')
{
msbuildLocation = helpers.getInputWithErrorCheck('msbuildLocation', 'Location of MSBuild.exe is required.');
}
return {
solution,
configuration,
msbuildArguments,
appxPackageBuildMode,
clean,
msbuildLocationMethod,
msbuildLocation,
msbuildVersion,
msbuildArchitecture
};
}
const getMSBuildPathFromVersion = async (msbuildVersion: string, msbuildArchitecture: string): Promise<string> =>
{
const osPlatform: string = os.platform();
if (osPlatform === 'win32')
{
// The Powershell helper only works on Windows;
// it looks in the Global Assembly Cache to find the right version.
// We use a wrapper script to call the right function from the helper.
const powershellRunner = tl.tool('powershell');
powershellRunner.arg(MSBUILD_PATH_HELPER_SCRIPT);
powershellRunner.arg(['-PreferredVersion', msbuildVersion]);
powershellRunner.arg(['-Architecture', msbuildArchitecture]);
const execResult = powershellRunner.execSync();
if (execResult.code)
{
throw execResult.stderr;
}
return execResult.stdout.trim();
}
else
{
// The TypeScript helper only works on Mac and Linux.
return await msbuildHelpers.getMSBuildPath(msbuildVersion);
}
}
const getMSBuildToolRunner = (
msbuildToolPath: string,
solutionFile: string,
createBundle: boolean,
outputPath: string,
platforms: string[],
configuration: string,
msbuildArguments: string,
appxPackageBuildMode: string
) : ToolRunner =>
{
const buildTool: ToolRunner = tl.tool(msbuildToolPath);
buildTool.arg(solutionFile);
// If we don't specify a platform when bundling, MSBuild may use one we are not building and cause an error.
buildTool.arg('/p:Platform=' + platforms[0]);
buildTool.arg('/p:Configuration=' + configuration);
buildTool.arg('/p:UapAppxPackageBuildMode=' + appxPackageBuildMode);
if (msbuildArguments)
{
buildTool.line(msbuildArguments);
}
// Add arguments specific for bundles/packages
if (createBundle)
{
buildTool.arg('/p:AppxBundle=Always');
buildTool.arg('/p:AppxBundleOutput=' + outputPath);
buildTool.arg('/p:AppxBundlePlatforms=' + platforms.join('|'));
}
else
{
buildTool.arg('/p:AppxBundle=Never');
buildTool.arg('/p:AppxPackageOutput=' + outputPath);
}
return buildTool;
}
export const runMSBuild = async (
createBundle: boolean,
outputPath: string,
platforms: string[],
{
solution,
configuration,
msbuildArguments,
appxPackageBuildMode,
clean,
msbuildLocationMethod,
msbuildLocation,
msbuildVersion,
msbuildArchitecture,
}: MSBuildCommonParameters) =>
{
const msbuildTool: string = msbuildLocationMethod === 'location' ? msbuildLocation! : await getMSBuildPathFromVersion(msbuildVersion!, msbuildArchitecture!);
const filesList: string[] = tl.findMatch('', solution, { followSymbolicLinks: false, followSpecifiedSymbolicLink: false, allowBrokenSymbolicLinks: false }, { matchBase: true });
// We only build a single file.
const file: string = filesList[0];
if (clean)
{
const cleanTool: ToolRunner = getMSBuildToolRunner(msbuildTool, file, createBundle, outputPath, platforms, configuration, msbuildArguments, appxPackageBuildMode);
cleanTool.arg('/t:Clean');
await cleanTool.exec();
}
const buildTool: ToolRunner = getMSBuildToolRunner(msbuildTool, file, createBundle, outputPath, platforms, configuration, msbuildArguments, appxPackageBuildMode);
await buildTool.exec();
}

286
tools/pipelines-tasks/MsixPackaging/package-lock.json сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,286 @@
{
"name": "msix-tasks-packaging",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/node": {
"version": "14.6.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.4.tgz",
"integrity": "sha512-Wk7nG1JSaMfMpoMJDKUsWYugliB2Vy55pdjLpmLixeyMi7HizW2I/9QoxsPCkXl3dO+ZOVqPumKaDUv5zJu2uQ=="
},
"@types/xml2js": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.5.tgz",
"integrity": "sha512-yohU3zMn0fkhlape1nxXG2bLEGZRc1FeqF80RoHaYXJN7uibaauXfhzhOJr1Xh36sn+/tx21QAOf07b/xYVk1w==",
"requires": {
"@types/node": "*"
}
},
"adm-zip": {
"version": "0.4.16",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz",
"integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg=="
},
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"azure-devops-node-api": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-10.1.1.tgz",
"integrity": "sha512-P4Hyrh/+Nzc2KXQk73z72/GsenSWIH5o8uiyELqykJYs9TWTVCxVwghoR7lPeiY6QVoXkq2S2KtvAgi5fyjl9w==",
"requires": {
"tunnel": "0.0.6",
"typed-rest-client": "^1.7.3",
"underscore": "1.8.3"
}
},
"azure-pipelines-task-lib": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.10.0.tgz",
"integrity": "sha512-nmwf4ReXGfaBDMRO08/KSDOqbieJFljQSXd6bSFl28QsOKiGy5qz1O7pMnb9UqYfH5Fbro0zU4Q88hpO0XkFHg==",
"requires": {
"minimatch": "3.0.4",
"mockery": "^1.7.0",
"q": "^1.1.2",
"semver": "^5.1.0",
"shelljs": "^0.3.0",
"sync-request": "3.0.1",
"uuid": "^3.0.1"
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
},
"caseless": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
"integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c="
},
"common": {
"version": "file:../common/msix-tasks-helpers-1.0.0.tgz",
"integrity": "sha512-JqVtP3csFwsJmfeEfendFrjUE4R53/jVf1NIpB7at7SYM9dEXYvCibctQUztM58vqwJ7/Bh6Io/Gbd7mW677zQ==",
"requires": {
"@types/xml2js": "^0.4.5",
"adm-zip": "^0.4.16",
"azure-devops-node-api": "^10.1.1",
"azure-pipelines-task-lib": "^2.9.5",
"xml2js": "^0.4.23"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"http-basic": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/http-basic/-/http-basic-2.5.1.tgz",
"integrity": "sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=",
"requires": {
"caseless": "~0.11.0",
"concat-stream": "^1.4.6",
"http-response-object": "^1.0.0"
}
},
"http-response-object": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-1.1.0.tgz",
"integrity": "sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM="
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"mockery": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/mockery/-/mockery-1.7.0.tgz",
"integrity": "sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "~2.0.3"
}
},
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
},
"qs": {
"version": "6.9.4",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
"integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ=="
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"shelljs": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
"integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"sync-request": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/sync-request/-/sync-request-3.0.1.tgz",
"integrity": "sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=",
"requires": {
"concat-stream": "^1.4.7",
"http-response-object": "^1.0.1",
"then-request": "^2.0.1"
}
},
"then-request": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/then-request/-/then-request-2.2.0.tgz",
"integrity": "sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=",
"requires": {
"caseless": "~0.11.0",
"concat-stream": "^1.4.7",
"http-basic": "^2.5.1",
"http-response-object": "^1.1.0",
"promise": "^7.1.1",
"qs": "^6.1.0"
}
},
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"typed-rest-client": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.7.3.tgz",
"integrity": "sha512-CwTpx/TkRHGZoHkJhBcp4X8K3/WtlzSHVQR0OIFnt10j4tgy4ypgq/SrrgVpA1s6tAL49Q6J3R5C0Cgfh2ddqA==",
"requires": {
"qs": "^6.9.1",
"tunnel": "0.0.6",
"underscore": "1.8.3"
}
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"underscore": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
},
"xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"requires": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
}
},
"xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
}
}
}

Просмотреть файл

@ -0,0 +1,20 @@
{
"name": "msix-tasks-packaging",
"version": "1.0.0",
"description": "Task for building and packaging MSIX apps",
"repository": {
"type": "git",
"url": "git+github.com/microsoft/msix-ado-tasks-extension.git"
},
"scripts": {},
"author": "Microsoft Coporation",
"license": "MIT",
"dependencies": {
"azure-devops-node-api": "^10.1.1",
"azure-pipelines-task-lib": "^2.9.5",
"common": "file:../common/msix-tasks-helpers-1.0.0.tgz"
},
"devDependencies": {
"@types/node": "^14.0.5"
}
}

Просмотреть файл

@ -0,0 +1,232 @@
{
"$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
"id": "e8789f65-a0e2-472b-98ca-8cfd83ccc3c3",
"name": "MsixPackaging",
"friendlyName": "MSIX build and package",
"instanceNameFormat": "MSIX build and package",
"description": "Build and package Windows apps using the MSIX package format",
"author": "Microsoft Corporation",
"category": "Package",
"helpMarkDown": "",
"execution": {
"Node10": {
"target": "index.js"
}
},
"version": {
"Major": 1,
"Minor": 0,
"Patch": 0
},
"demands": [
"msbuild"
],
"minimumAgentVersion": "1.95.0",
"groups": [
{
"name": "msbuild",
"displayName": "Advanced Options for MSBuild",
"isExpanded": false
}
],
"inputs": [
{
"name": "outputPath",
"type": "string",
"label": "Output Path",
"defaultValue": "",
"required": true,
"helpMarkDown": "Path of the generated package or bundle."
},
{
"name": "buildSolution",
"type": "boolean",
"label": "Build Solution with MSBuild",
"defaultValue": "true",
"helpMarkDown": "Invoke MSBuild and build the solution from scratch. If this is selected, you must provide a path to the solution file to build and select the target platforms to build."
},
{
"name": "inputDirectory",
"type": "string",
"label": "Input Directory",
"required": true,
"helpMarkDown": "Relative path from the repo root to the directory with the files to be packaged.",
"visibleRule": "buildSolution = false"
},
{
"name": "solution",
"type": "filePath",
"label": "Project to Build",
"defaultValue": "**/*.sln",
"required": true,
"helpMarkDown": "Relative path from repo root of the project or solution to build. Wildcards can be used.",
"visibleRule": "buildSolution = true"
},
{
"name": "clean",
"type": "boolean",
"label": "Clean Before Building",
"defaultValue": false,
"required": true,
"helpMarkDown": "Run a clean build (/t:clean) prior to the build.",
"visibleRule": "buildSolution = true"
},
{
"name": "generateBundle",
"type": "boolean",
"label": "Generate MSIX Bundle",
"defaultValue": false,
"required": true,
"helpMarkDown": "Generate an MSIX bundle."
},
{
"name": "buildConfiguration",
"type": "pickList",
"label": "Configuration",
"defaultValue": "debug",
"helpMarkDown": "The configuration to build the solution with. Only one configuration is supported at a time.",
"required": true,
"options": {
"debug": "Debug",
"release": "Release"
},
"visibleRule": "buildSolution = true"
},
{
"name": "buildPlatform",
"type": "string",
"label": "Platform",
"defaultValue": "",
"helpMarkDown": "Specify the platform you want to build such as Win32, x86, x64 or any cpu.",
"required": true,
"visibleRule": "buildSolution = true && generateBundle = false"
},
{
"name": "buildForX86",
"type": "boolean",
"label": "Build for x86",
"defaultValue": true,
"helpMarkDown": "Build the solution for the x86 platform.",
"visibleRule": "buildSolution = true && generateBundle = true"
},
{
"name": "buildForX64",
"type": "boolean",
"label": "Build for x64",
"defaultValue": true,
"helpMarkDown": "Build the solution for the x64 platform.",
"visibleRule": "buildSolution = true && generateBundle = true"
},
{
"name": "buildForArm",
"type": "boolean",
"label": "Build for ARM",
"defaultValue": false,
"helpMarkDown": "Build the solution for the ARM platform.",
"visibleRule": "buildSolution = true && generateBundle = true"
},
{
"name": "buildForAnyCpu",
"type": "boolean",
"label": "Build for Any CPU",
"defaultValue": false,
"helpMarkDown": "Build the solution for the Any CPU platform.",
"visibleRule": "buildSolution = true && generateBundle = true"
},
{
"name": "updateAppVersion",
"type": "boolean",
"label": "Update App Version in Manifest",
"defaultValue": false,
"required": true,
"helpMarkDown": "Update the app version from the one in the manifest."
},
{
"name": "manifestFile",
"type": "filePath",
"label": "Manifest File to Update Version",
"defaultValue": "",
"required": true,
"helpMarkDown": "Path to the manifest file. This is only used to update the app version.",
"visibleRule": "updateAppVersion = true"
},
{
"name": "appVersion",
"type": "string",
"label": "App Version",
"defaultValue": "1.0.0.0",
"required": true,
"helpMarkDown": "Version number to set for the app.",
"visibleRule": "updateAppVersion = true"
},
{
"name": "appPackageDistributionMode",
"type": "pickList",
"label": "Application Package Distribution Mode",
"defaultValue": "StoreAndSideload",
"required": true,
"helpMarkDown": "Whether to generate the .msixupload file for Store upload, the .msix/.msixbundle for non-Store apps, or both.",
"options": {
"SideloadOnly": "Create an application package (.msix) or bundle (.msixbundle) for non-Store app",
"StoreOnly": "Create an application package upload file (.msixupload) for Store app",
"StoreAndSideload": "Both"
},
"visibleRule": "buildSolution = true"
},
{
"name": "msbuildLocationMethod",
"type": "radio",
"label": "MSBuild",
"required": true,
"defaultValue": "version",
"groupName": "msbuild",
"options": {
"version": "Version",
"location": "Specify Location"
},
"visibleRule": "buildSolution = true"
},
{
"name": "msbuildVersion",
"type": "pickList",
"label": "MSBuild Version",
"required": true,
"defaultValue": "latest",
"groupName": "msbuild",
"helpMarkDown": "If the preferred version cannot be found, the latest version found will be used instead.",
"visibleRule": "buildSolution = true && msbuildLocationMethod = version",
"options": {
"latest": "Latest",
"16.0": "MSBuild 16.0",
"15.0": "MSBuild 15.0",
"14.0": "MSBuild 14.0",
"12.0": "MSBuild 12.0",
"4.0": "MSBuild 4.0"
}
},
{
"name": "msbuildArchitecture",
"type": "pickList",
"label": "MSBuild Architecture",
"defaultValue": "x86",
"required": true,
"groupName": "msbuild",
"helpMarkDown": "Optionally supply the architecture (x86, x64) of MSBuild to run.",
"visibleRule": "buildSolution = true && msbuildLocationMethod = version",
"options": {
"x86": "MSBuild x86",
"x64": "MSBuild x64"
}
},
{
"name": "msbuildLocation",
"type": "string",
"label": "Path to MSBuild",
"defaultValue": "",
"groupName": "msbuild",
"required": true,
"helpMarkDown": "Optionally supply the path to MSBuild.",
"visibleRule": "buildSolution = true && msbuildLocationMethod = location"
}
]
}

Просмотреть файл

@ -0,0 +1,232 @@
{
"$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
"id": "e8789f65-a0e2-472b-98ca-8cfd83ccc3c3",
"name": "MsixPackaging",
"friendlyName": "ms-resource:loc.friendlyName",
"instanceNameFormat": "ms-resource:loc.instanceNameFormat",
"description": "ms-resource:loc.description",
"author": "Microsoft Corporation",
"category": "Package",
"helpMarkDown": "ms-resource:loc.helpMarkDown",
"execution": {
"Node10": {
"target": "index.js"
}
},
"version": {
"Major": 1,
"Minor": 0,
"Patch": 0
},
"demands": [
"msbuild"
],
"minimumAgentVersion": "1.95.0",
"groups": [
{
"name": "msbuild",
"displayName": "ms-resource:loc.group.displayName.msbuild",
"isExpanded": false
}
],
"inputs": [
{
"name": "outputPath",
"type": "string",
"label": "ms-resource:loc.input.label.outputPath",
"defaultValue": "",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.outputPath"
},
{
"name": "buildSolution",
"type": "boolean",
"label": "ms-resource:loc.input.label.buildSolution",
"defaultValue": "true",
"helpMarkDown": "ms-resource:loc.input.help.buildSolution"
},
{
"name": "inputDirectory",
"type": "string",
"label": "ms-resource:loc.input.label.inputDirectory",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.inputDirectory",
"visibleRule": "buildSolution = false"
},
{
"name": "solution",
"type": "filePath",
"label": "ms-resource:loc.input.label.solution",
"defaultValue": "**/*.sln",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.solution",
"visibleRule": "buildSolution = true"
},
{
"name": "clean",
"type": "boolean",
"label": "ms-resource:loc.input.label.clean",
"defaultValue": false,
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.clean",
"visibleRule": "buildSolution = true"
},
{
"name": "generateBundle",
"type": "boolean",
"label": "ms-resource:loc.input.label.generateBundle",
"defaultValue": false,
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.generateBundle"
},
{
"name": "buildConfiguration",
"type": "pickList",
"label": "ms-resource:loc.input.label.buildConfiguration",
"defaultValue": "debug",
"helpMarkDown": "ms-resource:loc.input.help.buildConfiguration",
"required": true,
"options": {
"debug": "Debug",
"release": "Release"
},
"visibleRule": "buildSolution = true"
},
{
"name": "buildPlatform",
"type": "string",
"label": "ms-resource:loc.input.label.buildPlatform",
"defaultValue": "",
"helpMarkDown": "ms-resource:loc.input.help.buildPlatform",
"required": true,
"visibleRule": "buildSolution = true && generateBundle = false"
},
{
"name": "buildForX86",
"type": "boolean",
"label": "ms-resource:loc.input.label.buildForX86",
"defaultValue": true,
"helpMarkDown": "ms-resource:loc.input.help.buildForX86",
"visibleRule": "buildSolution = true && generateBundle = true"
},
{
"name": "buildForX64",
"type": "boolean",
"label": "ms-resource:loc.input.label.buildForX64",
"defaultValue": true,
"helpMarkDown": "ms-resource:loc.input.help.buildForX64",
"visibleRule": "buildSolution = true && generateBundle = true"
},
{
"name": "buildForArm",
"type": "boolean",
"label": "ms-resource:loc.input.label.buildForArm",
"defaultValue": false,
"helpMarkDown": "ms-resource:loc.input.help.buildForArm",
"visibleRule": "buildSolution = true && generateBundle = true"
},
{
"name": "buildForAnyCpu",
"type": "boolean",
"label": "ms-resource:loc.input.label.buildForAnyCpu",
"defaultValue": false,
"helpMarkDown": "ms-resource:loc.input.help.buildForAnyCpu",
"visibleRule": "buildSolution = true && generateBundle = true"
},
{
"name": "updateAppVersion",
"type": "boolean",
"label": "ms-resource:loc.input.label.updateAppVersion",
"defaultValue": false,
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.updateAppVersion"
},
{
"name": "manifestFile",
"type": "filePath",
"label": "ms-resource:loc.input.label.manifestFile",
"defaultValue": "",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.manifestFile",
"visibleRule": "updateAppVersion = true"
},
{
"name": "appVersion",
"type": "string",
"label": "ms-resource:loc.input.label.appVersion",
"defaultValue": "1.0.0.0",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.appVersion",
"visibleRule": "updateAppVersion = true"
},
{
"name": "appPackageDistributionMode",
"type": "pickList",
"label": "ms-resource:loc.input.label.appPackageDistributionMode",
"defaultValue": "StoreAndSideload",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.appPackageDistributionMode",
"options": {
"SideloadOnly": "Create an application package (.msix) or bundle (.msixbundle) for non-Store app",
"StoreOnly": "Create an application package upload file (.msixupload) for Store app",
"StoreAndSideload": "Both"
},
"visibleRule": "buildSolution = true"
},
{
"name": "msbuildLocationMethod",
"type": "radio",
"label": "ms-resource:loc.input.label.msbuildLocationMethod",
"required": true,
"defaultValue": "version",
"groupName": "msbuild",
"options": {
"version": "Version",
"location": "Specify Location"
},
"visibleRule": "buildSolution = true"
},
{
"name": "msbuildVersion",
"type": "pickList",
"label": "ms-resource:loc.input.label.msbuildVersion",
"required": true,
"defaultValue": "latest",
"groupName": "msbuild",
"helpMarkDown": "ms-resource:loc.input.help.msbuildVersion",
"visibleRule": "buildSolution = true && msbuildLocationMethod = version",
"options": {
"latest": "Latest",
"16.0": "MSBuild 16.0",
"15.0": "MSBuild 15.0",
"14.0": "MSBuild 14.0",
"12.0": "MSBuild 12.0",
"4.0": "MSBuild 4.0"
}
},
{
"name": "msbuildArchitecture",
"type": "pickList",
"label": "ms-resource:loc.input.label.msbuildArchitecture",
"defaultValue": "x86",
"required": true,
"groupName": "msbuild",
"helpMarkDown": "ms-resource:loc.input.help.msbuildArchitecture",
"visibleRule": "buildSolution = true && msbuildLocationMethod = version",
"options": {
"x86": "MSBuild x86",
"x64": "MSBuild x64"
}
},
{
"name": "msbuildLocation",
"type": "string",
"label": "ms-resource:loc.input.label.msbuildLocation",
"defaultValue": "",
"groupName": "msbuild",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.msbuildLocation",
"visibleRule": "buildSolution = true && msbuildLocationMethod = location"
}
]
}

Просмотреть файл

@ -0,0 +1,3 @@
{
"extends": "../tsconfig.json"
}

Просмотреть файл

@ -0,0 +1,14 @@
{
"loc.friendlyName": "MSIX package signing",
"loc.helpMarkDown": "",
"loc.description": "Sign MSIX packages",
"loc.instanceNameFormat": "Sign MSIX package",
"loc.input.label.package": "Package to sign",
"loc.input.help.package": "Files to sign. Can be a package or a bundle. All matching files are signed.",
"loc.input.label.certificate": "Certificate File",
"loc.input.help.certificate": "The file name or GUID of the secure certificate to use for signing. The file will be deleted after the pipeline runs.",
"loc.input.label.passwordVariable": "Password Variable",
"loc.input.help.passwordVariable": "The name of the variable which stores the password used to access the certificate file for signing. Note that this is NOT the password itself, but rather the variable name, which can be set under Library.",
"loc.input.label.timeStampServer": "Time Stamp Server",
"loc.input.help.timeStampServer": "A URL that specifies the address of a time stamping server."
}

Просмотреть файл

@ -0,0 +1,7 @@
# Set the task's inputs here to use when debugging
INPUT_PACKAGE=test\assets\existingPackage.msix
INPUT_CERTIFICATE=test\assets\certificate.pfx
INPUT_PASSWORDVARIABLE=secretPasswordVariable
SECRET_SECRETPASSWORDVARIABLE=password
INPUT_TIMESTAMPSERVER=

Двоичные данные
tools/pipelines-tasks/MsixSigning/icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Просмотреть файл

@ -0,0 +1,86 @@
import path = require('path');
import tl = require('azure-pipelines-task-lib/task')
import { ToolRunner } from 'azure-pipelines-task-lib/toolrunner';
import helpers = require('common/helpers');
import download = require('./predownloadsecurefile');
const SIGNTOOL_PATH = path.join(__dirname, 'lib', 'signtool');
/**
* Signs a package or bundle.
* @param packagePath Path to the package to sign.
* @param certificateFilePath Path to the certificate to use for signing.
* @param timeStampServer Time stamp server to use. Can be undefined if no time stamp is needed.
* @param password Password for the certificate. Can be undefined if not needed.
*/
const signPackage = async (packagePath: string, certificateFilePath: string, password: string | undefined, timeStampServer: string | undefined) =>
{
const signtoolRunner: ToolRunner = tl.tool(SIGNTOOL_PATH);
// Base arguments
signtoolRunner.line('sign /a /v /fd SHA256');
// Certificate to use
signtoolRunner.arg(['/f', certificateFilePath]);
if (password)
{
signtoolRunner.arg(['/p', password]);
}
// Time stamp options
if (timeStampServer)
{
signtoolRunner.arg(['/tr', timeStampServer, '/td', 'SHA256']);
}
signtoolRunner.arg(packagePath);
await signtoolRunner.exec();
}
/**
* Main function for the task.
*/
const run = async () =>
{
tl.setResourcePath(path.join(__dirname, 'task.json'));
const packagePathPattern: string = helpers.getInputWithErrorCheck('package', 'No package path specified.');
// Download certificate stored as secure file
const certificateSecureFileId: string = helpers.getInputWithErrorCheck('certificate', 'A certificate input is required for download to sign the app.');
const certificateFilePath: string = await download.downloadSecureFile(certificateSecureFileId, /* retryCount */ 5);
// Get the certificate password.
// Instead of parsing a password for the certificate as a plain string, we attempt to get the password as
// a secret variable saved to the pipeline from a variable group.
// No password variable means the certificate doens't need a password.
const passwordVariable: string | undefined = tl.getInput('passwordVariable');
let password: string | undefined;
if (passwordVariable)
{
password = tl.getVariable(passwordVariable);
if (password === undefined)
{
throw Error('The secret variable given does not point to a valid password.');
}
}
// No time stamp server means to not add a time stamp.
const timeStampServer: string | undefined = tl.getInput('timeStampServer');
// Resolve the package paths.
const packagesToSign: string[] = tl.findMatch(/* defaultRoot */ '', packagePathPattern);
// Sign the packages
for (const packagePath of packagesToSign)
{
await signPackage(packagePath, certificateFilePath, password, timeStampServer);
}
}
run().catch(err =>
{
tl.setResult(tl.TaskResult.Failed, err.message);
})

Двоичные данные
tools/pipelines-tasks/MsixSigning/lib/signtool.exe Normal file

Двоичный файл не отображается.

294
tools/pipelines-tasks/MsixSigning/package-lock.json сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,294 @@
{
"name": "msix-tasks-signing",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/node": {
"version": "14.6.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.3.tgz",
"integrity": "sha512-pC/hkcREG6YfDfui1FBmj8e20jFU5Exjw4NYDm8kEdrW+mOh0T1Zve8DWKnS7ZIZvgncrctcNCXF4Q2I+loyww=="
},
"@types/q": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz",
"integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==",
"dev": true
},
"@types/xml2js": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.5.tgz",
"integrity": "sha512-yohU3zMn0fkhlape1nxXG2bLEGZRc1FeqF80RoHaYXJN7uibaauXfhzhOJr1Xh36sn+/tx21QAOf07b/xYVk1w==",
"requires": {
"@types/node": "*"
}
},
"adm-zip": {
"version": "0.4.16",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz",
"integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg=="
},
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"azure-devops-node-api": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-10.1.1.tgz",
"integrity": "sha512-P4Hyrh/+Nzc2KXQk73z72/GsenSWIH5o8uiyELqykJYs9TWTVCxVwghoR7lPeiY6QVoXkq2S2KtvAgi5fyjl9w==",
"requires": {
"tunnel": "0.0.6",
"typed-rest-client": "^1.7.3",
"underscore": "1.8.3"
}
},
"azure-pipelines-task-lib": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.10.0.tgz",
"integrity": "sha512-nmwf4ReXGfaBDMRO08/KSDOqbieJFljQSXd6bSFl28QsOKiGy5qz1O7pMnb9UqYfH5Fbro0zU4Q88hpO0XkFHg==",
"requires": {
"minimatch": "3.0.4",
"mockery": "^1.7.0",
"q": "^1.1.2",
"semver": "^5.1.0",
"shelljs": "^0.3.0",
"sync-request": "3.0.1",
"uuid": "^3.0.1"
},
"dependencies": {
"caseless": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
"integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c="
},
"http-basic": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/http-basic/-/http-basic-2.5.1.tgz",
"integrity": "sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=",
"requires": {
"caseless": "~0.11.0",
"concat-stream": "^1.4.6",
"http-response-object": "^1.0.0"
}
},
"http-response-object": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-1.1.0.tgz",
"integrity": "sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM="
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "~2.0.3"
}
},
"sync-request": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/sync-request/-/sync-request-3.0.1.tgz",
"integrity": "sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=",
"requires": {
"concat-stream": "^1.4.7",
"http-response-object": "^1.0.1",
"then-request": "^2.0.1"
}
},
"then-request": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/then-request/-/then-request-2.2.0.tgz",
"integrity": "sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=",
"requires": {
"caseless": "~0.11.0",
"concat-stream": "^1.4.7",
"http-basic": "^2.5.1",
"http-response-object": "^1.1.0",
"promise": "^7.1.1",
"qs": "^6.1.0"
}
}
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
},
"common": {
"version": "file:../common/msix-tasks-helpers-1.0.0.tgz",
"integrity": "sha512-JqVtP3csFwsJmfeEfendFrjUE4R53/jVf1NIpB7at7SYM9dEXYvCibctQUztM58vqwJ7/Bh6Io/Gbd7mW677zQ==",
"requires": {
"@types/xml2js": "^0.4.5",
"adm-zip": "^0.4.16",
"azure-devops-node-api": "^10.1.1",
"azure-pipelines-task-lib": "^2.9.5",
"xml2js": "^0.4.23"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"mockery": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/mockery/-/mockery-1.7.0.tgz",
"integrity": "sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
},
"qs": {
"version": "6.9.4",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
"integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ=="
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"shelljs": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
"integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"typed-rest-client": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.7.3.tgz",
"integrity": "sha512-CwTpx/TkRHGZoHkJhBcp4X8K3/WtlzSHVQR0OIFnt10j4tgy4ypgq/SrrgVpA1s6tAL49Q6J3R5C0Cgfh2ddqA==",
"requires": {
"qs": "^6.9.1",
"tunnel": "0.0.6",
"underscore": "1.8.3"
}
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"underscore": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
},
"xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"requires": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
}
},
"xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
}
}
}

Просмотреть файл

@ -0,0 +1,21 @@
{
"name": "msix-tasks-signing",
"version": "1.0.0",
"description": "Task to sign MSIX packages",
"repository": {
"type": "git",
"url": "git+github.com/microsoft/msix-ado-tasks-extension.git"
},
"scripts": {},
"author": "Microsoft Coporation",
"license": "MIT",
"dependencies": {
"azure-devops-node-api": "^10.1.1",
"azure-pipelines-task-lib": "^2.9.5",
"common": "file:../common/msix-tasks-helpers-1.0.0.tgz"
},
"devDependencies": {
"@types/node": "^14.0.5",
"@types/q": "^1.5.4"
}
}

Просмотреть файл

@ -0,0 +1,22 @@
import tl = require('azure-pipelines-task-lib/task')
import secureFilesCommon = require('./securefiles-common/securefiles-common');
/**
* A small wrapper around the secure file helpers.
* This exists for easy mocking in unit tests.
*/
export const downloadSecureFile = async (secureFileId: string, retryCount: number): Promise<string> =>
{
// For local debugging.
if (process.argv.includes("--mockSecureFileDownload"))
{
return secureFileId;
}
console.log("downloading file with secureFileId:", secureFileId);
const secureFileHelpers = new secureFilesCommon.SecureFileHelpers(retryCount);
const secureFilePath: string = await secureFileHelpers.downloadSecureFile(secureFileId);
console.log("file downloaded");
return secureFilePath;
}

Просмотреть файл

@ -0,0 +1,30 @@
import * as tl from "azure-pipelines-task-lib/task";
export class SecureFileHelpers {
private static fileExtension: string = ".filename";
constructor(retryCount?: number) {
tl.debug('Mock SecureFileHelpers constructor');
if (retryCount) {
tl.debug('Mock SecureFileHelpers retry count set to: ' + retryCount);
} else {
tl.debug('Mock SecureFileHelpers retry count not set.');
}
}
async downloadSecureFile(secureFileId: string) {
tl.debug('Mock downloadSecureFile with id = ' + secureFileId);
const fileName: string = `${secureFileId}${SecureFileHelpers.fileExtension}`;
const tempDownloadPath: string = `/build/temp/${fileName}`;
return tempDownloadPath;
}
deleteSecureFile(secureFileId: string) {
tl.debug('Mock deleteSecureFile with id = ' + secureFileId);
}
static setFileExtension(extension: string): void {
this.fileExtension = extension;
}
}

Просмотреть файл

@ -0,0 +1,96 @@
import * as fs from 'fs';
import * as Q from 'q';
import * as tl from 'azure-pipelines-task-lib/task';
import { getPersonalAccessTokenHandler, WebApi } from 'azure-devops-node-api';
import { IRequestOptions } from "azure-devops-node-api/interfaces/common/VsoBaseInterfaces";
export class SecureFileHelpers {
serverConnection: WebApi;
constructor(retryCount?: number) {
const serverUrl: string | undefined = tl.getVariable('System.TeamFoundationCollectionUri');
if (!serverUrl) {
throw ReferenceError("Argument serverUrl is required but not given.");
}
const serverCreds: string | undefined = tl.getEndpointAuthorizationParameter('SYSTEMVSSCONNECTION', 'ACCESSTOKEN', false);
console.log("serverCreds:", serverCreds);
if (!serverCreds) {
throw ReferenceError("Argument serverCreds is required but not given.");
}
const authHandler = getPersonalAccessTokenHandler(serverCreds);
const maxRetries = retryCount && retryCount >= 0 ? retryCount : 5; // Default to 5 if not specified
tl.debug('Secure file retry count set to: ' + maxRetries);
const proxy = tl.getHttpProxyConfiguration();
let options: IRequestOptions = {
allowRetries: true,
maxRetries
};
console.log("proxy:", proxy);
if (proxy) {
options = { ...options, proxy, ignoreSslError: true };
};
this.serverConnection = new WebApi(serverUrl, authHandler, options);
}
/**
* Download secure file contents to a temporary location for the build
* @param secureFileId
*/
async downloadSecureFile(secureFileId: string): Promise<string> {
const tempDownloadPath: string = this.getSecureFileTempDownloadPath(secureFileId);
tl.debug('Downloading secure file contents to: ' + tempDownloadPath);
const file: NodeJS.WritableStream = fs.createWriteStream(tempDownloadPath);
const agentApi = await this.serverConnection.getTaskAgentApi();
const ticket = tl.getSecureFileTicket(secureFileId);
if (!ticket) {
// Workaround bug #7491. tl.loc only works if the consuming tasks define the resource string.
throw new Error(`Download ticket for SecureFileId ${secureFileId} not found.`);
}
let fileToDownload: string | undefined = tl.getVariable('SYSTEM.TEAMPROJECT');
if (!fileToDownload) {
throw ReferenceError("Cannot get file to download");
}
const stream = (await agentApi.downloadSecureFile(fileToDownload, secureFileId, ticket, false)).pipe(file);
const defer = Q.defer();
stream.on('finish', () => {
defer.resolve();
});
await defer.promise;
tl.debug('Downloaded secure file contents to: ' + tempDownloadPath);
return tempDownloadPath;
}
/**
* Delete secure file from the temporary location for the build
* @param secureFileId
*/
deleteSecureFile(secureFileId: string): void {
const tempDownloadPath: string = this.getSecureFileTempDownloadPath(secureFileId);
if (tl.exist(tempDownloadPath)) {
tl.debug('Deleting secure file at: ' + tempDownloadPath);
tl.rmRF(tempDownloadPath);
}
}
/**
* Returns the temporary download location for the secure file
* @param secureFileId
*/
getSecureFileTempDownloadPath(secureFileId: string): string {
const fileName: string = tl.getSecureFileName(secureFileId);
return tl.resolve(tl.getVariable('Agent.TempDirectory'), fileName);
}
}

Просмотреть файл

@ -0,0 +1,53 @@
{
"$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
"id": "501a9528-7fa4-4cb5-b8da-79ded62b74eb",
"name": "MsixSigning",
"friendlyName": "MSIX package signing",
"instanceNameFormat": "Sign MSIX package",
"description": "Sign MSIX packages",
"author": "Microsoft Corporation",
"category": "Package",
"helpMarkDown": "",
"execution": {
"Node10": {
"target": "index.js"
}
},
"version": {
"Major": 1,
"Minor": 0,
"Patch": 0
},
"minimumAgentVersion": "1.95.0",
"inputs": [
{
"name": "package",
"type": "string",
"label": "Package to sign",
"defaultValue": "$(Build.ArtifactStagingDirectory)\\**\\*.msix*",
"required": true,
"helpMarkDown": "Files to sign. Can be a package or a bundle. All matching files are signed."
},
{
"name": "certificate",
"type": "secureFile",
"label": "Certificate File",
"required": true,
"helpMarkDown": "The file name or GUID of the secure certificate to use for signing. The file will be deleted after the pipeline runs."
},
{
"name": "passwordVariable",
"type": "string",
"label": "Password Variable",
"required": true,
"helpMarkDown": "The name of the variable which stores the password used to access the certificate file for signing. Note that this is NOT the password itself, but rather the variable name, which can be set under Library."
},
{
"name": "timeStampServer",
"type": "string",
"label": "Time Stamp Server",
"required": false,
"helpMarkDown": "A URL that specifies the address of a time stamping server."
}
]
}

Просмотреть файл

@ -0,0 +1,53 @@
{
"$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
"id": "501a9528-7fa4-4cb5-b8da-79ded62b74eb",
"name": "MsixSigning",
"friendlyName": "ms-resource:loc.friendlyName",
"instanceNameFormat": "ms-resource:loc.instanceNameFormat",
"description": "ms-resource:loc.description",
"author": "Microsoft Corporation",
"category": "Package",
"helpMarkDown": "ms-resource:loc.helpMarkDown",
"execution": {
"Node10": {
"target": "index.js"
}
},
"version": {
"Major": 1,
"Minor": 0,
"Patch": 0
},
"minimumAgentVersion": "1.95.0",
"inputs": [
{
"name": "package",
"type": "string",
"label": "ms-resource:loc.input.label.package",
"defaultValue": "$(Build.ArtifactStagingDirectory)\\**\\*.msix*",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.package"
},
{
"name": "certificate",
"type": "secureFile",
"label": "ms-resource:loc.input.label.certificate",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.certificate"
},
{
"name": "passwordVariable",
"type": "string",
"label": "ms-resource:loc.input.label.passwordVariable",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.passwordVariable"
},
{
"name": "timeStampServer",
"type": "string",
"label": "ms-resource:loc.input.label.timeStampServer",
"required": false,
"helpMarkDown": "ms-resource:loc.input.help.timeStampServer"
}
]
}

Просмотреть файл

@ -0,0 +1,3 @@
{
"extends": "../tsconfig.json"
}

Просмотреть файл

@ -0,0 +1,50 @@
# Creates the .vsix package and publishes to your test publisher.
param(
[Parameter(Mandatory=$true)]
[string]
$publisherName,
[Parameter(Mandatory=$true)]
[string]
$extensionId
)
# Personal Access Token used to access the publisher account.
# This is requested the first time the script is run and is stored encrypted.
$marketplacePatLocation = "$PSScriptRoot\pat.txt"
function Set-MarketplacePat()
{
Read-Host -Prompt "PAT" | ConvertTo-SecureString -AsPlainText | ConvertFrom-SecureString | Set-Content -Path $marketplacePatLocation
}
function Get-MarketplacePat()
{
if (!(Test-Path $marketplacePatLocation))
{
Set-MarketplacePat
}
$securePassword = Get-Content $marketplacePatLocation | ConvertTo-SecureString
# On Powershell >= 7
# $securePassword | ConvertFrom-SecureString -AsPlainText
$credential = New-Object System.Management.Automation.PSCredential ("dummy", $securePassword)
return $credential.GetNetworkCredential().Password
}
function Update-TaskVersions()
{
foreach ($path in $(Get-ChildItem -Recurse -Depth 1 -Filter 'task.json')) {
$taskJson = Get-Content $path.FullName -Raw | ConvertFrom-Json
$taskJson.version.Patch += 1
$taskJson | ConvertTo-Json -Depth 10 | Set-Content $path.FullName
}
}
Push-Location $taskSrcRoot
Update-TaskVersions
& $PSScriptRoot/build.ps1 Build
tfx extension publish --manifests vss-extension.json --publisher $publisherName --extension-id $extensionId --rev-version --token $(Get-MarketplacePat)
Pop-Location

Просмотреть файл

@ -0,0 +1,48 @@
# MSIX ADO Tasks
This includes the source for Azure Pipelines tasks for:
* Building and packaging MSIX apps.
* Signing MSIX packages.
* Creating VHDX disks for use with MSIX app attach.
* Creating App Installer files.
## Building
You need to have Node.js v10 installed (higher versions cause problems with the tests).
When building for the first time, install the development tools (e.g. TypeScript) and dependencies (e.g. node modules) needed with:
```
.\build.ps1 InstallDevelopmentTools
.\build.ps1 InstallDependencies
```
To compile the project:
```
.\build.ps1 Build
```
You can also use `tsc`, but the script will also update the localization files if needed.
To build the common helpers and update the dependencies in other projects:
```
.\build.ps1 BuildCommonHelpers
```
To publish the extension to a private publisher:
```
.\PublishForTesting.ps1 -publisherName <your publisher name> -extensionId <extension name>
```
You will need to have a [Personal Access Token](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate).
This script is intended to publish to a private publisher to test changes, that is why
you need to set the publisher and use a different name for the extension.
It will auto-increase the patch version of the tasks and the extension.
To run the tests, from the project root (`/tools/pipelines-tasks/`) do:
```
mocha
```
## Updating dependencies
* MakeAppx.exe (under `.\common\lib`), SignTool.exe (under `.\MsixSigning\lib`) and related files were taken from the [MSIX Toolkit](https://github.com/microsoft/MSIX-Toolkit/tree/master/Redist.x86)
* msixmgr.exe (under `.\MsixAppAttach\lib`) was taken from the [MSIX Core 1.1. release](https://github.com/microsoft/msix-packaging/releases)
* The MSBuildHelpers at `.\MsixPackaging\MSBuildHelpers` were taken from [azure-pipelines-tasks](https://github.com/microsoft/azure-pipelines-tasks/tree/master/Tasks/Common/MSBuildHelpers). There were only a minor changes to type annotations to make it compile with our configuration.
* vswhere.exe under `.\MsixPackaging\MSBuildHelpers` was taken from [vswhere release 1.0.62](https://github.com/Microsoft/vswhere/releases/download/1.0.62/vswhere.exe)

Просмотреть файл

@ -0,0 +1,5 @@
<SignConfigXML>
<job platform="" configuration="" dest="__OUTPATHROOT__" jobname="ISS EngFun" approvers="" certSubject="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US">
<file src="__INPATHROOT__\MsixPackagingExtension.vsix" signType="AuthenticodeFormer" />
</job>
</SignConfigXML>

Просмотреть файл

@ -0,0 +1,49 @@
# Build and test pipeline for CI
# Branches that trigger a build on commit
trigger:
- master
- release_v*
# Branches that trigger builds on PR
pr:
branches:
include:
- master
- release_v*
paths:
include:
- tools/pipelines-tasks/*
pool:
vmImage: 'windows-latest'
variables:
tasksRoot: 'tools/pipelines-tasks'
steps:
- task: NodeTool@0
displayName: 'Use Node 10.x'
inputs:
versionSpec: 10.x
# Build the project
- task: PowerShell@2
displayName: 'Build the project'
inputs:
filePath: '$(tasksRoot)/build.ps1'
arguments: 'BuildForProduction'
# Run the tests
- task: NuGetCommand@2
displayName: 'Restore NuGet packages for test project'
inputs:
restoreSolution: '$(tasksRoot)/test/assets/HelloWorldUWPApp/HelloWorldApp.sln'
- powershell: |
npx mocha
displayName: 'Run the tests'
workingDirectory: '$(tasksRoot)'
env:
SYSTEM_CULTURE: 'en-US'

Просмотреть файл

@ -0,0 +1,68 @@
#
# Localization
# This pipeline uploads English strings files to the localization service, downloads any translated
# files which are available, and checks them in to git. This pipeline relies on Microsoft-internal
# resources to run.
#
# Expects a variable called LocServiceKey to contain the OAuth client secret for Touchdown.
trigger: none
pr: none
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
pool:
vmImage: windows-latest
variables:
tasksRoot: 'tools/pipelines-tasks'
skipComponentGovernanceDetection: true
steps:
- task: TouchdownBuildTask@1
displayName: Send resources to Touchdown Build
inputs:
teamId: 15687
authId: 2796a411-f030-46c1-ae3e-ab56f60ea523
authKey: $(LocServiceKey)
isPreview: false
relativePathRoot: '$(tasksRoot)'
resourceFilePath: '*\Strings\resources.resjson\en-US\resources.resjson'
appendRelativeDir: true
# TouchdownBuildTask will place the localized files under
# Strings\resources.resjson\en-US\
# We need to move them one level up
# E.g. move Strings\resources.resjson\en-US\fr-FR to make it Strings\resources.resjson\fr-FR
- powershell: |
# Repeat for each strings directory in all tasks
Get-ChildItem -Recurse -Depth 1 -Filter Strings | %{
$resourcesDir = Join-Path $_.FullName Resources.resjson
# Remove existing localized files
Get-ChildItem $resourcesDir -Exclude en-US | Remove-Item -Recurse
# Find the misplaced localized files and move them to the right place
Get-ChildItem $resourcesDir\en-US -Exclude resources.resjson | %{
Move-Item $_ $resourcesDir
}
}
displayName: Place loc files in the right location
workingDirectory: '$(tasksRoot)'
- script: |
cd $(Build.SourcesDirectory)
git add -A
git diff --cached --exit-code
echo ##vso[task.setvariable variable=hasChanges]%errorlevel%
git diff --cached > $(Build.ArtifactStagingDirectory)\LocalizedStrings.patch
displayName: Check for changes and create patch file
workingDirectory: '$(tasksRoot)'
- task: PublishPipelineArtifact@0
displayName: Publish patch file as artifact
condition: eq(variables['hasChanges'], '1')
inputs:
artifactName: Patch
targetPath: $(Build.ArtifactStagingDirectory)

Просмотреть файл

@ -0,0 +1,58 @@
# A sample pipeline using the tasks.
# The pipeline expects to have a secure file named certificate.pfx
# and a secret variable called Password.
variables:
tasksRoot: 'tools/pipelines-tasks'
solution: '$(tasksRoot)/test/assets/HelloWorldUWPApp/HelloWorldApp.sln'
manifest: '$(tasksRoot)/test/assets/HelloWorldUWPApp/Package.appxmanifest'
platform: 'x86'
package: '$(Build.ArtifactStagingDirectory)/package.msix'
pool:
vmImage: 'windows-latest'
steps:
- task: NuGetCommand@2
displayName: 'NuGet restore'
inputs:
restoreSolution: $(solution)
# Build the package
- task: MsixPackaging@0
inputs:
outputPath: $(package)
solution: $(solution)
clean: true
buildConfiguration: release
buildPlatform: $(platform)
updateAppVersion: true
manifestFile: $(manifest)
appVersion: '1.2.3.4'
- task: MsixSigning@0
inputs:
package: $(package)
certificate: 'certificate.pfx'
passwordVariable: 'Password'
- task: MsixAppAttach@0
inputs:
package: $(package)
vhdxOutputPath: '$(Build.ArtifactStagingDirectory)/App.vhdx'
vhdxSize: '5'
- task: AppInstallerFile@0
inputs:
package: $(package)
outputPath: '$(Build.ArtifactStagingDirectory)/App.appinstaller'
method: 'create'
fileVersion: '1.0.0.0'
uri: 'https://example.com/AppInstallerFile'
mainItemUri: 'https://example.com/App'
- task: PublishPipelineArtifact@1
displayName: 'Publish Pipeline Artifact'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)'

Просмотреть файл

@ -0,0 +1,209 @@
[CmdletBinding()]
param (
[string]
[ValidateSet(
'InstallDevelopmentTools',
'InstallDependencies',
'BuildCommonHelpers',
'Build',
'BuildForProduction'
)]
$action
)
$taskNames = (
"AppInstallerFile",
"MsixAppAttach",
"MsixPackaging",
"MsixSigning"
)
# npm likes writing to the stderr, which PS will sometimes interpret as an error.
# This wrapper lets us call it while temporarily disabling this error handling.
function npm
{
$oldErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = 'SilentlyContinue'
npm.cmd $args
$ErrorActionPreference = $oldErrorActionPreference
if ($LASTEXITCODE -ne 0)
{
throw "npm failed"
}
}
function OnDirectory([string]$dir, [scriptblock]$script, [object[]]$arguments)
{
Push-Location $dir
try
{
Invoke-Command $script -ArgumentList $arguments
}
finally
{
Pop-Location
}
}
function OnEachTask([string]$message, [scriptblock]$script)
{
foreach ($task in $taskNames)
{
Write-Host "$task : $message"
OnDirectory "$PSScriptRoot\$task" $script
}
}
# Builds the common helpers and installs it to each task.
# This needs to run after any changes to the common helpers.
function BuildCommonHelpers([switch]$installDependencies)
{
OnDirectory "$PSScriptRoot\common" -arguments $installDependencies {
param($installDependencies)
if ($installDependencies)
{
Write-Host "Installing dependencies"
npm ci
}
# Build the directory
Write-Host "Compiling common helpers"
npx tsc
if (-not $?)
{
throw "Failed to build 'common'"
}
# Pack the package for npm.
# We need to reference a .tgz package instead of a directory because
# tfx cannot deal with symbolic links.
#
# I.e. if we reference the package in the task's package.json as
# "dependencies": {
# "common": "../common"
# }
# then the task's node_modules/common will be a symbolic link to
# /common, and creating the extension with tfx will fail.
#
# Instead we reference the packaged common as
# "dependencies": {
# "common": "../common/msix-tasks-helpers-1.0.0.tgz"
# }
# This will copy and extract the package into the task's
# node_modules/.
#
# The downside of this is that it changes to common/ are not
# picked up by tasks, hence this function.
# Before packaging, remove existing packages so they are not
# included in new package.
Remove-Item *.tgz
Write-Host "Packaging common helpers"
npm pack
# Install the package to all the tasks.
# The helpers need to be installed to each task because each task is
# installed independently to the agent, so only files on the task's
# directory can be used.
OnEachTask "Installing common helpers" {
npm install common
}
}
}
# Installs the development tools required to work on the repo.
# This needs Node.js v10 to already be installed, and will only install the
# required global Node modules
function InstallDevelopmentTools()
{
# Typescript compiler
npm install -g typescript
# CLI tools to interact with Azure DevOps (e.g. build and publish the extension)
npm install -g tfx-cli
# Test platform
npm install -g mocha
}
# Installs the dependencies for every project (the common helpers and all tasks)
function InstallAllDepenencies()
{
# Always prefer 'npm ci' over 'npm install' to use specific package versions
# from package-lock.json and get the same results on any machine.
# First build the common helpers as they are a dependency of everything else.
BuildCommonHelpers -installDependencies
# Install dependencies for top level scripts.
OnDirectory $PSScriptRoot {
npm ci
}
# Install dependencies for each task.
# This will install the common helpers again, but it's not too much extra work.
OnEachTask "Install dependencies" {
npm ci
}
OnDirectory $PSScriptRoot\MsixPackaging {
if (-not (Test-Path ps_modules/VstsTaskSdk))
{
Write-Host "Installing VSTS Task SDK Powershell Module"
New-Item -Type Directory ps_modules -ErrorAction SilentlyContinue
Save-Module -Name VstsTaskSdk -Path .\ps_modules\
}
}
# Create a test certificate for local testing/debugging.
# This creates the file expected by the tests and debug inputs.
$cert = New-SelfSignedCertificate -Type Custom -Subject "CN=HelloWorldPublisher" -KeyUsage DigitalSignature -FriendlyName "HelloWorldPublisher" -CertStoreLocation "Cert:\CurrentUser\My" -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3", "2.5.29.19={text}")
$certPath = "Cert:\CurrentUser\My\$($cert.Thumbprint)"
$password = ConvertTo-SecureString -String password -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath $PSScriptRoot\test\assets\certificate.pfx -Password $password
Remove-Item $certPath
}
# Build all the tasks and update the loc strings.
function Build() {
Write-Host "Build all directories and update loc files"
OnDirectory $PSScriptRoot {
npx tsc
node create-resjson.js
}
}
# Build all the tasks and removes development dependencies.
# This doesn't create the extension .vsix package.
function BuildForProduction()
{
InstallDevelopmentTools
InstallAllDepenencies
Build
# Fail if loc files changed.
# This is to cause the pipelines to fail if the changes were not commited.
# Ignore changes to package-lock.json as it will contain a new hash for the common helpers.
$filesModified = git status --porcelain | Where-Object { $_ -notmatch 'package-lock.json' }
if ($filesModified)
{
$filesModified
throw "There are uncommited changes to loc strings"
}
OnEachTask "Remove development dependencies" {
npm prune
}
}
switch ($action)
{
'InstallDevelopmentTools' { InstallDevelopmentTools }
'InstallDependencies' { InstallAllDepenencies }
'BuildCommonHelpers' { BuildCommonHelpers }
'Build' {Build}
'BuildForProduction' { BuildForProduction }
}

Просмотреть файл

@ -0,0 +1,100 @@
import fs = require('fs');
import os = require('os');
import path = require('path');
import tl = require('azure-pipelines-task-lib/task');
import xml = require('xml2js');
import { ToolRunner } from 'azure-pipelines-task-lib/toolrunner';
export const MAKEAPPX_PATH = path.join(__dirname, 'lib', 'makeappx');
/**
* When running on an agent, returns the value of Agent.TempDirectory which is cleaned after
* each pipeline job. When running locally, returns the local temp directory.
*/
export const getTempDirectory = (): string =>
{
return tl.getVariable('Agent.TempDirectory') ?? os.tmpdir();
}
/**
* Gets an input variable, checking that it is present and throwing if it's not.
* @param variableName Name of the input variable to get.
* @param errorMessage Message to include in the error if the variable is empty, null or undefined.
* @returns The value of the input variable if it is set.
*/
export const getInputWithErrorCheck = (variableName: string, errorMessage: string): string =>
{
const variableValue: string | undefined = tl.getInput(variableName);
if (!variableValue)
{
throw Error('Input Error: ' + errorMessage);
}
return variableValue;
}
/**
* Increment the current version given by the method specified. A version
* is in the form of (major).(minor).(build).(revision). The incremental
* method specifies which part of the version to increment. For example,
* if the current version given is 1.0.0.0 and the incrementalMethod = 'revision',
* then '1.0.0.1' is returned.
* @param currentVersion
* @param incrementalMethod
*/
export const incrementVersion = (currentVersion: string[], incrementalMethod: string): string =>
{
const methodToIndex: { [method: string]: number } =
{
'revision': 3,
'build': 2,
'minor': 1,
'major': 0
}
if (!Object.keys(methodToIndex).includes(incrementalMethod))
{
throw Error(`"${incrementalMethod}" is not a valid method to increment the version.`);
}
// TODO: roll over if maximum reached?
const index: number = methodToIndex[incrementalMethod];
currentVersion[index] = (parseInt(currentVersion[index]) + 1).toString();
for (let a: number = index + 1; a < 4; a++)
{
currentVersion[a] = '0';
}
return currentVersion.join('.')
}
/**
* Unpack/unbundle a package or bundle and put the outputs into <outputDirectory>.
* @param filePath the path to the file which we wish to unpack/unbundle
* @param outputDirectory the directory where the content of the unpacked file will be deposited to
* @param isBundle whether or not the given file is a bundle
*/
export const unpackFile = async (filePath: string, outputDirectory: string, isBundle: boolean) =>
{
const makeAppxRunner: ToolRunner = tl.tool(MAKEAPPX_PATH);
makeAppxRunner.arg(isBundle ? 'unbundle' : 'unpack');
makeAppxRunner.arg(['-p', filePath]);
makeAppxRunner.arg(['-d', outputDirectory]);
makeAppxRunner.arg('-o');
await makeAppxRunner.exec();
}
export const parseXml = async (filePath: string): Promise<any> =>
{
const fileText: string = fs.readFileSync(filePath).toString();
const parser = new xml.Parser();
return await parser.parseStringPromise(fileText);
}
export const writeXml = (xmlObject: any, filePath: string) =>
{
const xmlBuilder = new xml.Builder();
fs.writeFileSync(filePath, xmlBuilder.buildObject(xmlObject));
}

Двоичные данные
tools/pipelines-tasks/common/lib/AppxPackaging.dll.mui Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
name="Microsoft.Windows.Build.Appx.AppxPackaging.dll"
version="0.0.0.0"/>
<file name="AppxPackaging.dll">
<comClass
clsid="{5842a140-ff9f-4166-8f5c-62f5b7b0c781}"
threadingModel="Both"
description="AppxFactory class"/>
<comClass
clsid="{DC664FDD-D868-46EE-8780-8D196CB739F7}"
threadingModel="Both"
description="AppxEncryptionFactory class"/>
<comClass
clsid="{378E0446-5384-43B7-8877-E7DBDD883446}"
threadingModel="Both"
description="AppxBundleFactory class"/>
<comClass
clsid="{48DE828C-730C-49AF-AE84-759C609911EE}"
threadingModel="Both"
description="AppxNoValidationFactory class"/>
<comClass
clsid="{F004F2CA-AEBC-4B0D-BF58-E516D5BCC0AB}"
threadingModel="Both"
description="AppxPackageEditor class"/>
<comClass
clsid="{7F00FA1E-9820-47B1-9C4F-8701F1432177}"
threadingModel="Both"
description="AppxPackagingLayoutReader class"/>
<comClass
clsid="{0CF07551-EEF2-420C-B5AB-7E4FEB2249CF}"
threadingModel="Both"
description="AppxFactoryInternal class"/>
<comClass
clsid="{50CA0A46-1588-4161-8ED2-EF9E469CED5D}"
threadingModel="Both"
description="AppxPackagingDiagnosticEventSinkManager class"/>
</file>
<dependency>
<dependentAssembly>
<assemblyIdentity
name="Microsoft.Windows.Build.Appx.OpcServices.dll"
version="0.0.0.0"/>
</dependentAssembly>
</dependency>
</assembly>

Просмотреть файл

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
name="Microsoft.Windows.Build.Appx.AppxSip.dll"
version="0.0.0.0"/>
<file name="AppxSip.dll"/>
<dependency>
<dependentAssembly>
<assemblyIdentity
name="Microsoft.Windows.Build.Appx.AppxPackaging.dll"
version="0.0.0.0"/>
</dependentAssembly>
</dependency>
</assembly>

Просмотреть файл

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
name="Microsoft.Windows.Build.Appx.OpcServices.dll"
version="0.0.0.0"/>
<file name="OpcServices.dll">
<comClass
clsid="{6B2D6BA0-9F3E-4f27-920B-313CC426A39E}"
threadingModel="Both"
description="OpcFactory class"/>
</file>
</assembly>

Двоичные данные
tools/pipelines-tasks/common/lib/appxpackaging.dll Normal file

Двоичный файл не отображается.

Двоичные данные
tools/pipelines-tasks/common/lib/appxsip.dll Normal file

Двоичный файл не отображается.

Двоичные данные
tools/pipelines-tasks/common/lib/makeappx.exe Normal file

Двоичный файл не отображается.

Двоичные данные
tools/pipelines-tasks/common/lib/makepri.exe Normal file

Двоичный файл не отображается.

Двоичные данные
tools/pipelines-tasks/common/lib/opcservices.dll Normal file

Двоичный файл не отображается.

421
tools/pipelines-tasks/common/package-lock.json сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,421 @@
{
"name": "msix-tasks-helpers",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/concat-stream": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.0.tgz",
"integrity": "sha1-OU2+C7X+5Gs42JZzXoto7yOQ0A0=",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/form-data": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz",
"integrity": "sha1-yayFsqX9GENbjIXZ7LUObWyJP/g=",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/mocha": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz",
"integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==",
"dev": true
},
"@types/node": {
"version": "14.6.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.3.tgz",
"integrity": "sha512-pC/hkcREG6YfDfui1FBmj8e20jFU5Exjw4NYDm8kEdrW+mOh0T1Zve8DWKnS7ZIZvgncrctcNCXF4Q2I+loyww=="
},
"@types/q": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz",
"integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==",
"dev": true
},
"@types/qs": {
"version": "6.9.4",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.4.tgz",
"integrity": "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==",
"dev": true
},
"@types/xml2js": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.5.tgz",
"integrity": "sha512-yohU3zMn0fkhlape1nxXG2bLEGZRc1FeqF80RoHaYXJN7uibaauXfhzhOJr1Xh36sn+/tx21QAOf07b/xYVk1w==",
"requires": {
"@types/node": "*"
}
},
"adm-zip": {
"version": "0.4.16",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz",
"integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg=="
},
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=",
"dev": true
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
"dev": true
},
"azure-devops-node-api": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-10.1.1.tgz",
"integrity": "sha512-P4Hyrh/+Nzc2KXQk73z72/GsenSWIH5o8uiyELqykJYs9TWTVCxVwghoR7lPeiY6QVoXkq2S2KtvAgi5fyjl9w==",
"requires": {
"tunnel": "0.0.6",
"typed-rest-client": "^1.7.3",
"underscore": "1.8.3"
}
},
"azure-pipelines-task-lib": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.10.0.tgz",
"integrity": "sha512-nmwf4ReXGfaBDMRO08/KSDOqbieJFljQSXd6bSFl28QsOKiGy5qz1O7pMnb9UqYfH5Fbro0zU4Q88hpO0XkFHg==",
"requires": {
"minimatch": "3.0.4",
"mockery": "^1.7.0",
"q": "^1.1.2",
"semver": "^5.1.0",
"shelljs": "^0.3.0",
"uuid": "^3.0.1"
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"dev": true
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
"requires": {
"delayed-stream": "~1.0.0"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
},
"form-data": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
"dev": true,
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
},
"get-port": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz",
"integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=",
"dev": true
},
"http-basic": {
"version": "8.1.3",
"resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz",
"integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==",
"dev": true,
"requires": {
"caseless": "^0.12.0",
"concat-stream": "^1.6.2",
"http-response-object": "^3.0.1",
"parse-cache-control": "^1.0.1"
}
},
"http-response-object": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz",
"integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==",
"dev": true,
"requires": {
"@types/node": "^10.0.3"
},
"dependencies": {
"@types/node": {
"version": "10.17.29",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.29.tgz",
"integrity": "sha512-zLo9rjUeQ5+QVhOufDwrb3XKyso31fJBJnk9wUUQIBDExF/O4LryvpOfozfUaxgqifTnlt7FyqsAPXUq5yFZSA==",
"dev": true
}
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true
},
"mime-db": {
"version": "1.44.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
"dev": true
},
"mime-types": {
"version": "2.1.27",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
"dev": true,
"requires": {
"mime-db": "1.44.0"
}
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"mockery": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/mockery/-/mockery-1.7.0.tgz",
"integrity": "sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8="
},
"parse-cache-control": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz",
"integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104=",
"dev": true
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"dev": true
},
"promise": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz",
"integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==",
"dev": true,
"requires": {
"asap": "~2.0.6"
}
},
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
},
"qs": {
"version": "6.9.4",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
"integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ=="
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"shelljs": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
"integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
"safe-buffer": "~5.1.0"
}
},
"sync-request": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz",
"integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==",
"dev": true,
"requires": {
"http-response-object": "^3.0.1",
"sync-rpc": "^1.2.1",
"then-request": "^6.0.0"
}
},
"sync-rpc": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz",
"integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==",
"dev": true,
"requires": {
"get-port": "^3.1.0"
}
},
"then-request": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz",
"integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==",
"dev": true,
"requires": {
"@types/concat-stream": "^1.6.0",
"@types/form-data": "0.0.33",
"@types/node": "^8.0.0",
"@types/qs": "^6.2.31",
"caseless": "~0.12.0",
"concat-stream": "^1.6.0",
"form-data": "^2.2.0",
"http-basic": "^8.1.1",
"http-response-object": "^3.0.1",
"promise": "^8.0.0",
"qs": "^6.4.0"
},
"dependencies": {
"@types/node": {
"version": "8.10.63",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.63.tgz",
"integrity": "sha512-g+nSkeHFDd2WOQChfmy9SAXLywT47WZBrGS/NC5ym5PJ8c8RC6l4pbGaUW/X0+eZJnXw6/AVNEouXWhV4iz72Q==",
"dev": true
}
}
},
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"typed-rest-client": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.7.3.tgz",
"integrity": "sha512-CwTpx/TkRHGZoHkJhBcp4X8K3/WtlzSHVQR0OIFnt10j4tgy4ypgq/SrrgVpA1s6tAL49Q6J3R5C0Cgfh2ddqA==",
"requires": {
"qs": "^6.9.1",
"tunnel": "0.0.6",
"underscore": "1.8.3"
}
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
"underscore": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
},
"xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"requires": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
}
},
"xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
}
}
}

Просмотреть файл

@ -0,0 +1,25 @@
{
"name": "msix-tasks-helpers",
"version": "1.0.0",
"description": "Common helpers for the MSIX packaging tasks",
"repository": {
"type": "git",
"url": "git+github.com/microsoft/msix-ado-tasks-extension.git"
},
"scripts": {},
"author": "Microsoft Coporation",
"license": "MIT",
"dependencies": {
"@types/xml2js": "^0.4.5",
"adm-zip": "^0.4.16",
"azure-devops-node-api": "^10.1.1",
"azure-pipelines-task-lib": "^2.9.5",
"xml2js": "^0.4.23"
},
"devDependencies": {
"@types/mocha": "^7.0.2",
"@types/node": "^14.0.5",
"@types/q": "^1.5.4",
"sync-request": "^6.1.0"
}
}

Просмотреть файл

@ -0,0 +1,3 @@
{
"extends": "../tsconfig.json"
}

Просмотреть файл

@ -0,0 +1,148 @@
// Adapted from github.com/microsoft/azure-pipelines-tasks/
import fs = require('fs');
import os = require('os');
import path = require('path');
import shell = require('shelljs');
const taskNames: string[] =
[
'AppInstallerFile',
'MsixAppAttach',
'MsixPackaging',
'MsixSigning',
]
const shellAssert = () => {
var errMsg = shell.error();
if (errMsg) {
throw new Error(errMsg);
}
};
const mkdir = (options: string, target: string) => {
if (target) {
shell.mkdir(options, target);
}
else {
shell.mkdir(options);
}
shellAssert();
}
const fileToJson = (file: string) => {
var jsonFromFile = JSON.parse(fs.readFileSync(file).toString());
return jsonFromFile;
}
const createResjson = (task: any, taskPath: string) => {
const resources: any = {};
if (task.hasOwnProperty('friendlyName')) {
resources['loc.friendlyName'] = task.friendlyName;
}
if (task.hasOwnProperty('helpMarkDown')) {
resources['loc.helpMarkDown'] = task.helpMarkDown;
}
if (task.hasOwnProperty('description')) {
resources['loc.description'] = task.description;
}
if (task.hasOwnProperty('instanceNameFormat')) {
resources['loc.instanceNameFormat'] = task.instanceNameFormat;
}
if (task.hasOwnProperty('releaseNotes')) {
resources['loc.releaseNotes'] = task.releaseNotes;
}
if (task.hasOwnProperty('groups')) {
task.groups.forEach(function (group: any) {
if (group.hasOwnProperty('name')) {
resources['loc.group.displayName.' + group.name] = group.displayName;
}
});
}
if (task.hasOwnProperty('inputs')) {
task.inputs.forEach(function (input: any) {
if (input.hasOwnProperty('name')) {
resources['loc.input.label.' + input.name] = input.label;
if (input.hasOwnProperty('helpMarkDown') && input.helpMarkDown) {
resources['loc.input.help.' + input.name] = input.helpMarkDown;
}
}
});
}
if (task.hasOwnProperty('messages')) {
Object.keys(task.messages).forEach(function (key: any) {
resources['loc.messages.' + key] = task.messages[key];
});
}
var resjsonPath = path.join(taskPath, 'Strings', 'resources.resjson', 'en-US', 'resources.resjson');
mkdir('-p', path.dirname(resjsonPath));
var resjsonContent = JSON.stringify(resources, null, /* space */ 2);
if (process.platform == 'win32') {
resjsonContent = resjsonContent.replace(/\n/g, os.EOL);
}
fs.writeFileSync(resjsonPath, resjsonContent);
};
const createTaskLocJson = (taskPath: string) => {
const taskJsonPath = path.join(taskPath, 'task.json');
const taskLoc: any = fileToJson(taskJsonPath);
taskLoc.friendlyName = 'ms-resource:loc.friendlyName';
taskLoc.helpMarkDown = 'ms-resource:loc.helpMarkDown';
taskLoc.description = 'ms-resource:loc.description';
taskLoc.instanceNameFormat = 'ms-resource:loc.instanceNameFormat';
if (taskLoc.hasOwnProperty('releaseNotes')) {
taskLoc.releaseNotes = 'ms-resource:loc.releaseNotes';
}
if (taskLoc.hasOwnProperty('groups')) {
taskLoc.groups.forEach(function (group: any) {
if (group.hasOwnProperty('name')) {
group.displayName = 'ms-resource:loc.group.displayName.' + group.name;
}
});
}
if (taskLoc.hasOwnProperty('inputs')) {
taskLoc.inputs.forEach(function (input: any) {
if (input.hasOwnProperty('name')) {
input.label = 'ms-resource:loc.input.label.' + input.name;
if (input.hasOwnProperty('helpMarkDown') && input.helpMarkDown) {
input.helpMarkDown = 'ms-resource:loc.input.help.' + input.name;
}
}
});
}
if (taskLoc.hasOwnProperty('messages')) {
Object.keys(taskLoc.messages).forEach(function (key) {
taskLoc.messages[key] = 'ms-resource:loc.messages.' + key;
});
}
var taskLocContent = JSON.stringify(taskLoc, null, 2);
if (process.platform == 'win32') {
taskLocContent = taskLocContent.replace(/\n/g, os.EOL);
}
fs.writeFileSync(path.join(taskPath, 'task.loc.json'), taskLocContent);
};
for (const taskName of taskNames)
{
const taskPath = path.join(__dirname, taskName);
const taskJsonPath = path.join(taskPath, 'task.json');
const taskJson = fileToJson(taskJsonPath);
// create loc files
createTaskLocJson(taskPath);
createResjson(taskJson, taskPath);
}

Двоичные данные
tools/pipelines-tasks/images/extension-icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

3066
tools/pipelines-tasks/package-lock.json сгенерированный Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,32 @@
{
"name": "msix-ado-tasks-extension",
"version": "1.0.0",
"description": "",
"main": "createResjson.js",
"scripts": {},
"repository": {
"type": "git",
"url": "git+https://github.com/microsoft/msix-ado-tasks-extension.git"
},
"author": "Microsoft Corporation",
"license": "MIT",
"bugs": {
"url": "https://github.com/microsoft/msix-ado-tasks-extension/issues"
},
"homepage": "https://github.com/microsoft/msix-ado-tasks-extension#readme",
"dependencies": {
"azure-devops-node-api": "^10.1.1",
"azure-pipelines-task-lib": "^2.9.5",
"shelljs": "^0.8.4"
},
"devDependencies": {
"@types/mocha": "^7.0.2",
"@types/node": "^14.0.5",
"@types/q": "^1.5.4",
"@types/shelljs": "^0.8.8",
"mocha": "^8.1.3",
"sync-request": "^6.1.0",
"tfx-cli": "^0.8.2",
"typescript": "^4.0.2"
}
}

Просмотреть файл

@ -0,0 +1,15 @@
import assert = require('assert');
import ttm = require('azure-pipelines-task-lib/mock-test');
import testHelpers = require('./testhelpers');
describe('MSIX app attach task tests', function ()
{
it('Should succeed with basic inputs', function (done: Mocha.Done)
{
const testRunner: ttm.MockTestRunner = testHelpers.runMockTest('appattach-success.js');
testHelpers.assertTestRunnerSucceeded(testRunner);
assert.strictEqual(testHelpers.outputFileExists('TestVhdx.vhdx'), true, 'The VHDX should have been created');
done();
});
});

Просмотреть файл

@ -0,0 +1,49 @@
import assert = require('assert');
import childProcess = require('child_process');
import fs = require('fs');
import ttm = require('azure-pipelines-task-lib/mock-test');
import testHelpers = require('./testhelpers');
const runTestAndVerifyFileIsAsExpected = (testName: string) =>
{
const testRunner: ttm.MockTestRunner = testHelpers.runMockTest(testName + '.js');
testHelpers.assertTestRunnerSucceeded(testRunner);
testHelpers.assertOutputFileExists(testName + '.appinstaller');
const createdFilePath = testHelpers.outputFilePath(testName + '.appinstaller');
const expectedFilePath = testHelpers.expectedFilePath(testName + '.appinstaller');
// Using Compare-Object instead of comparing the files ourselves
// prevents errors due to mismatched line endings.
const diff = childProcess.execSync(`powershell Compare-Object (Get-Content ${createdFilePath}) (Get-Content ${createdFilePath})`).toString();
assert.strictEqual(diff, '', `There should be no difference between the expected .appinstaller '${expectedFilePath}' and created .appinstaller '${createdFilePath}'.`);
}
describe('App Installer file task tests', function ()
{
it('Should succeed creating a new App Installer file from a bundle', function (done: Mocha.Done)
{
runTestAndVerifyFileIsAsExpected('appinstallerfile-new-from-bundle-success');
done();
});
it('Should succeed updating an exsiting App Installer file from a bundle', function (done: Mocha.Done)
{
runTestAndVerifyFileIsAsExpected('appinstallerfile-update-from-bundle-success');
done();
});
it('Should succeed creating a new App Installer file from a package', function (done: Mocha.Done)
{
runTestAndVerifyFileIsAsExpected('appinstallerfile-new-from-package-success');
done();
});
it('Should succeed updating an existing App Installer file from a package', function (done: Mocha.Done)
{
runTestAndVerifyFileIsAsExpected('appinstallerfile-update-from-package-success');
done();
});
});

Просмотреть файл

@ -0,0 +1,7 @@
<Application
x:Class="HelloWorldApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:HelloWorldApp">
</Application>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше