Add project for Azure Pipelines Tasks for MSIX (#384)
This commit is contained in:
Родитель
a967283997
Коммит
bdb5d41520
|
@ -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
|
|
@ -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
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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);
|
||||
})
|
|
@ -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
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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);
|
||||
})
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -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;
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
Двоичный файл не отображается.
|
@ -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
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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();
|
||||
}
|
|
@ -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=
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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);
|
||||
})
|
Двоичный файл не отображается.
|
@ -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));
|
||||
}
|
Двоичный файл не отображается.
|
@ -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>
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -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);
|
||||
}
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.5 KiB |
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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>
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче