diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/README.md b/Tasks/AzureResourceManagerTemplateDeploymentV3/README.md new file mode 100644 index 000000000000..3e0ecc13e4f0 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/README.md @@ -0,0 +1,111 @@ +# Azure Resource Manager (ARM) Template Deployment Task + +### Overview + +This task is used to deploy [Azure Resource Manager templates](https://azure.microsoft.com/en-in/documentation/articles/resource-group-template-deploy/) at resource group deployment scope, subscription deployment scope and management group [deployment scopes](https://docs.microsoft.com/bs-latn-ba/Azure/azure-resource-manager/resource-group-template-deploy-rest#deployment-scope). The task is also used to create or update a resource group in Azure. + +### What's new in Version 3.0 + - Added support for Subscription and Management Group deployment scopes. + - Removed all the VM related actions. + + +### Contact Information +Please report a problem at [Developer Community Forum](https://developercommunity.visualstudio.com/spaces/21/index.html) if you are facing problems in making this task work. You can also share feedback about the task like, what more functionality should be added to the task, what other tasks you would like to have, at the same place. + + +### Prerequisite for the task + +#### Azure Subscription + +To deploy to Azure, an Azure subscription has to be linked to Team Foundation Server or to Azure Pipelines using the Services tab in the Account Administration section. Add the Azure subscription to use in the Build or Release Management definition by opening the Account Administration screen (gear icon on the top-right of the screen) and then click on the Services Tab. Create a service endpoint of 'Azure Resource Manager' type. For more troubleshooting guidance around endpoint creation, refer [this](https://www.visualstudio.com/en-us/docs/build/actions/azure-rm-endpoint). + +For Azure MSDN accounts, one can either use a [Service Principal](https://go.microsoft.com/fwlink/?LinkID=623000&clcid=0x409) or a work account. It's easy to create a work account as shown below: + +1. Create an user in the Azure Active Directory from the [portal](https://msdn.microsoft.com/en-us/library/azure/hh967632.aspx) (this is the old Azure portal). After adding the account, the following two things need to be done to use the organization in Azure Pipelines: + - Add the Active Directory account to the co-administrators in the subscription. Go to the Settings and then click on administrators and add the account as a co-admin like, [testuser@joehotmail.onmicrosoft.com](mailto:testuser@joehotmail.onmicrosoft.com) + - Login to the portal with this Active Directory account wiz. [testuser@joehotmail.onmicrosoft.com](mailto:testuser@joehotmail.onmicrosoft.com), and change the password. Initially a temporary password is created and that needs to be changed at the first login. +2. Add that user and password in the service connections in Azure Pipelines and deployments will work with that account. + +#### Azure PowerShell + +The task needs the Azure PowerShell version to be installed on the automation agent, and that can be done easily using the [Azure PowerShell Installer v1.0.2](https://github.com/Azure/azure-powershell/releases/tag/v1.0.2-December2015). Refer to "Supported Azure and AzureRM module versions" section below for recommended versions. + +### Parameters of the task: + +The parameters of the task are described in details, including examples, to show how to input the parameters. The parameters listed with a \* are required parameters for the task: + + * **Deployment Scope**\*: Select the scope of deployment from the options: Resource Group, Subscription and Mangement Group. For more info refer this [link](https://docs.microsoft.com/bs-latn-ba/Azure/azure-resource-manager/resource-group-template-deploy-rest#deployment-scope) + + * **Azure Resource Manager connection**\*: Select the ARM service connection with appropriate access i.e. the ARM service connection should have access to the resource group, subscription or the management group where the ARM template is targetted. To configure new service connection, select the Azure subscription from the list and click 'Authorize'. If your subscription is not listed or if you want to use an existing Service Principal, you can setup an Azure service connection using 'Manage' link. + + * **Subscription**\*: Select the subscripton to which the deployment is targetted. + + * **Action**\*: If the deployment scope is 'Resource Group', select the action to be performed on the resource group. Following actions are available: + - Create or Update Resource Group: creates a new resource group or to update an existing one (using [Azure Resource Manager templates](https://azure.microsoft.com/en-in/documentation/articles/resource-group-template-deploy/)). + - Delete Resource Group + + * **Resource Group**\*: Enter the name of the resource group. If this is an existing resource group, and the selected action is to create or update the resource group, then the task will update the resource group with the resources specified in the Azure template. If no Resource Group with the name exists in the subscription, then a new one will be created. + + * **Location**\*: + - For Resource Group deployment scope: Location for deploying the resource group. If the resource group already exists in the subscription, then this value will be ignored. + - For other deployment scopes: Location for storing the deployment metadata. + + * **Template location**: The location of the Template & the Parameters JSON files. Select "Linked Artifact" if the files are part of the linked code/build artifacts. Select "URL of the file" if the JSON files are located at any publicly accessible http/https URLs. To use a file stored in a private storage account, retrieve and include the shared access signature (SAS) token in the URL of the template. Example: /template.json?. To upload a parameters file to a storage account and generate a SAS token, you could use [Azure file copy task](https://aka.ms/azurefilecopyreadme) or follow the steps using [PowerShell](https://go.microsoft.com/fwlink/?linkid=838080) or [Azure CLI](https://go.microsoft.com/fwlink/?linkid=836911). + + * **Template and its Parameters**: The templates and the templates parameters file are the Azure templates available at [GitHub](https://github.com/Azure/azure-quickstart-templates) or in the [Azure gallery](https://azure.microsoft.com/en-in/documentation/articles/powershell-azure-resource-manager/). To get started immediately use [this](https://aka.ms/sampletemplate) template that is available on GitHub. + - These files can be either be located at any publicly accessible http/https URLs or be in a checked in the Version Control or they can be part of the build itself. If the files are part of the Build, use the pre-defined [system variables](https://msdn.microsoft.com/Library/vs/alm/Build/scripts/variables) provided by the Build to specify their location. The variables to use are $(Build.Repository.LocalPath), if the templates are checked-in but are not built, or $(Agent.BuildDirectory), if the templates are built as part of the solution. Be sure to specify the full path like $(Build.Repository.LocalPath)\Azure Templates\AzureRGDeploy.json. Wildcards like \*\*\\\*.json or \*\*\\*.param.json are also supported and there needs to be only one file that matches the search pattern at the location. If more than one file matches the search pattern, then the task will error out. + + **NOTE**: Follow the Azure Naming guidelines while specifying parameters, few important one mentioned in below table_ + +| Kind | Length | Casing | Valid Chars | Globally Unique | +|:--------------------:|--------|------------------|---------------------------------------------------------------------------------------|:---------------:| +| Storage Account | 3-24 | lowercase | alphanumeric | Yes | +| Azure Resource Group | 2-64 | case-insensitive | alphanumeric periods, underscores, hyphens and parenthesis and cannot end in a period | No | +| Azure KeyVault | 3-24 | case-insensitive | alphanumeric | Yes | +| Azure DNS Name | 3-63 | lowercase | alphanumeric and hyphens | Yes | + + * **Override Template Parameters**: The Override template parameters is used to override the parameters, like `-storageAcctName azurerg -Username $(vmusername) -azureKeyVaultName $(fabrikamFibre)`. To avoid storing "secureString" parameters in plain text, it is recommended that you use secret variables, for example `$(variableName)`. By clicking on “…” next to Override template parameters textbox, template parameters can be viewed/overridden in a grid. This feature requires that CORS rules are enabled at the source. If templates are in Azure storage blob, refer to [this](https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Cross-Origin-Resource-Sharing--CORS--Support-for-the-Azure-Storage-Services?redirectedfrom=MSDN#understanding-cors-requests) to enable CORS. + + * **Deployment Mode**: This specifies the [deployment mode](https://azure.microsoft.com/en-us/documentation/articles/resource-group-template-deploy) in which the Azure resources specified in the template have to be deployed. Incremental mode handles deployments as incremental updates to the resource group . It leaves unchanged resources that exist in the resource group but are not specified in the template. Complete mode deletes resources that are not in your template. [Validate mode](https://msdn.microsoft.com/en-us/library/azure/dn790547.aspx) enables you to find syntactical problems with the template before creating actual resources. By default, incremental mode is used. + + ### Deployment Outputs: + Outputs created by Azure Resource Manager template deployment. It can be used in the subsequent tasks (like Powershell and Azure CLI) for further processing. + + **How to use Deployment output** + The deployment output can be parsed to JSON object using "ConvertFrom-Json" Powershell cmdlet in Powershell/Azure Powershell task and then that object can be used in same task or subsequent tasks. + + Example: + ``` + $var=ConvertFrom-Json '$(storageAccountName)' + $value=$var.storageAccountName.value + Write-Host "##vso[task.setvariable variable=storageAccount;]$value" + ``` + + On linux agent, same technique can be used to create a JSON object. However, if you want to avoid Powershell task, you can use a script similar to below which converts the Outputs to valid JSON by adding double quotes. + + ``` + var=`echo "$(storageAccountName)" | \ + sed -e 's/ //g' | \ + sed -e 's/}/"\n}/g' | \ + sed -e 's/{/{\n"/g' | \ + sed -e 's/:/":"/g' | \ + sed -e 's/,/",\n"/g' | \ + sed -e 's/"}/}/g' | \ + sed -e 's/}"/}/g' | \ + sed -e 's/"{/{/g' | \ + sed -e 's/\[/\[\n"/g' | \ + sed -e 's/]/"\n]/g' | \ + sed -e 's/"\[/\[/g' | \ + sed -e 's/]"/]/g'` + sa_name=`echo $var | jq -r .storageAccountName.value` + echo $sa_name + ``` + +### Supported Azure and AzureRM module versions: +| Azure Pipelines/TFS Release | Recommended Azure Version | Other Supported Versions | +|:------------------:|:---------------------------:|:-------------------------:| +| Azure Pipelines | [v1.3.2](https://github.com/Azure/azure-powershell/releases/tag/v1.3.2-April2016) | [v0.9.8](https://github.com/Azure/azure-powershell/releases/tag/v0.9.8-September2015) | +| TFS 2015 Update 3 | [v1.3.2](https://github.com/Azure/azure-powershell/releases/tag/v1.3.2-April2016) | [v0.9.8](https://github.com/Azure/azure-powershell/releases/tag/v0.9.8-September2015) | +| TFS 2015 Update 2 | [v1.0.2](https://github.com/Azure/azure-powershell/releases/tag/v1.0.2-December2015) | [v0.9.8](https://github.com/Azure/azure-powershell/releases/tag/v0.9.8-September2015) | +| TFS 2015 Update 1 | [v0.9.8](https://github.com/Azure/azure-powershell/releases/tag/v0.9.8-September2015) | | +| TFS 2015 RTM | [v0.9.8](https://github.com/Azure/azure-powershell/releases/tag/v0.9.8-September2015) | | diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Strings/resources.resjson/en-US/resources.resjson b/Tasks/AzureResourceManagerTemplateDeploymentV3/Strings/resources.resjson/en-US/resources.resjson new file mode 100644 index 000000000000..d29f0406c0d3 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Strings/resources.resjson/en-US/resources.resjson @@ -0,0 +1,85 @@ +{ + "loc.friendlyName": "ARM template deployment", + "loc.helpMarkDown": "[Learn more about this task](https://aka.ms/armtaskreadme)", + "loc.description": "Deploy an Azure Resource Manager (ARM) template to all the deployment scopes", + "loc.instanceNameFormat": "ARM Template deployment: $(deploymentScope) scope", + "loc.releaseNotes": "- Added support for deployment at all the deployment scopes.\n- Removed all the VM related actions.", + "loc.group.displayName.AzureDetails": "Azure Details", + "loc.group.displayName.Template": "Template", + "loc.group.displayName.Advanced": "Advanced", + "loc.input.label.deploymentScope": "Deployment scope", + "loc.input.help.deploymentScope": "Deployment scope of the deployment. To know more abour deployment scopes, refer this [link](https://docs.microsoft.com/bs-latn-ba/Azure/azure-resource-manager/resource-group-template-deploy-rest#deployment-scope)", + "loc.input.label.ConnectedServiceName": "Azure Resource Manager connection", + "loc.input.help.ConnectedServiceName": "Select the Azure Resource Manager service connection having access to the selected deployment scope.", + "loc.input.label.subscriptionName": "Subscription", + "loc.input.help.subscriptionName": "Select the Azure subscription", + "loc.input.label.action": "Action", + "loc.input.help.action": "Action to be performed on the Azure resources or resource group.", + "loc.input.label.resourceGroupName": "Resource group", + "loc.input.help.resourceGroupName": "Provide the name of a resource group.", + "loc.input.label.location": "Location", + "loc.input.help.location": "For Resource Group deployment scope: Location for deploying the resource group. If the resource group already exists in the subscription, then this value will be ignored.\n For other deployment scope: Location to store deployment metadata.", + "loc.input.label.templateLocation": "Template location", + "loc.input.label.csmFileLink": "Template link", + "loc.input.help.csmFileLink": "Specify the URL of the template file. Example: [https://raw.githubusercontent.com/Azure/...](https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/101-vm-simple-windows/azuredeploy.json) \n\nTo deploy a template stored in a private storage account, retrieve and include the shared access signature (SAS) token in the URL of the template. Example: `/template.json?` To upload a template file (or a linked template) to a storage account and generate a SAS token, you could use [Azure file copy](https://aka.ms/azurefilecopyreadme) task or follow the steps using [PowerShell](https://go.microsoft.com/fwlink/?linkid=838080) or [Azure CLI](https://go.microsoft.com/fwlink/?linkid=836911).\n\nTo view the template parameters in a grid, click on “…” next to Override template parameters text box. This feature requires that CORS rules are enabled at the source. If templates are in Azure storage blob, refer to [this](https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Cross-Origin-Resource-Sharing--CORS--Support-for-the-Azure-Storage-Services?redirectedfrom=MSDN#understanding-cors-requests) to enable CORS.", + "loc.input.label.csmParametersFileLink": "Template parameters link", + "loc.input.help.csmParametersFileLink": "Specify the URL of the parameters file. Example: [https://raw.githubusercontent.com/Azure/...](https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/101-vm-simple-windows/azuredeploy.parameters.json) \n\nTo use a file stored in a private storage account, retrieve and include the shared access signature (SAS) token in the URL of the template. Example: `/template.json?` To upload a parameters file to a storage account and generate a SAS token, you could use [Azure file copy](https://aka.ms/azurefilecopyreadme) task or follow the steps using [PowerShell](https://go.microsoft.com/fwlink/?linkid=838080) or [Azure CLI](https://go.microsoft.com/fwlink/?linkid=836911). \n\nTo view the template parameters in a grid, click on “…” next to Override template parameters text box. This feature requires that CORS rules are enabled at the source. If templates are in Azure storage blob, refer to [this](https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Cross-Origin-Resource-Sharing--CORS--Support-for-the-Azure-Storage-Services?redirectedfrom=MSDN#understanding-cors-requests) to enable CORS.", + "loc.input.label.csmFile": "Template", + "loc.input.help.csmFile": "Specify the path or a pattern pointing to the Azure Resource Manager template. For more information about the templates see https://aka.ms/azuretemplates. To get started immediately use template https://aka.ms/sampletemplate.", + "loc.input.label.csmParametersFile": "Template parameters", + "loc.input.help.csmParametersFile": "Specify the path or a pattern pointing for the parameters file for the Azure Resource Manager template.", + "loc.input.label.overrideParameters": "Override template parameters", + "loc.input.help.overrideParameters": "To view the template parameters in a grid, click on “…” next to Override Parameters textbox. This feature requires that CORS rules are enabled at the source. If templates are in Azure storage blob, refer to [this](https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Cross-Origin-Resource-Sharing--CORS--Support-for-the-Azure-Storage-Services?redirectedfrom=MSDN#understanding-cors-requests) to enable CORS. Or type the template parameters to override in the textbox. Example,
–storageName fabrikam –adminUsername $(vmusername) -adminPassword $(password) –azureKeyVaultName $(fabrikamFibre).
If the parameter value you're using has multiple words, enclose them in quotes, even if you're passing them using variables. For example, -name \"parameter value\" -name2 \"$(var)\"
To override object type parameters use stringified JSON objects. For example, -options [\"option1\"] -map {\"key1\": \"value1\" }. ", + "loc.input.label.deploymentMode": "Deployment mode", + "loc.input.help.deploymentMode": "Refer to [this](https://docs.microsoft.com/en-us/azure/azure-resource-manager/deployment-modes) for more details. \n\n Incremental mode handles deployments as incremental updates to the resource group. It leaves unchanged resources that exist in the resource group but are not specified in the template. \n\n Complete mode deletes resources that are not in your template. Complete mode takes relatively more time than incremental mode. If the task times out, consider increasing the timeout, or changing the mode to 'Incremental'. \n [Warning] This action will delete all the existing resources in the resource group that are not specified in the template. \n\n Validate mode enables you to find problems with the template before creating actual resources. \n\n By default, Incremental mode is used. \n\n 'Complete' mode is supported for 'Resource Group' Deployment scope only.", + "loc.input.label.deploymentName": "Deployment name", + "loc.input.help.deploymentName": "Specifies the name of the resource group deployment to create.", + "loc.input.label.deploymentOutputs": "Deployment outputs", + "loc.input.help.deploymentOutputs": "Provide a name for the variable for the output variable which will contain the outputs section of the current deployment object in string format. You can use the “ConvertFrom-Json” PowerShell cmdlet to parse the JSON object and access the individual output values. For more details refer to [this](https://github.com/microsoft/azure-pipelines-tasks/tree/master/Tasks/AzureResourceManagerTemplateDeploymentV3#deployment-outputs)", + "loc.input.label.addSpnToEnvironment": "Access service principal details in override parameters", + "loc.input.help.addSpnToEnvironment": "Adds service principal id and key of the Azure endpoint you chose to the script's execution environment. You can use these variables: `$servicePrincipalId` and `$servicePrincipalKey` in your override parameters like `-key $servicePrincipalKey`", + "loc.messages.CheckResourceGroupExistence": "Checking if the following resource group exists: %s.", + "loc.messages.ResourceGroupStatusFetchFailed": "Failed to check the resource group status. Error: %s.", + "loc.messages.ResourceGroupStatus": "Resource group exists: %s.", + "loc.messages.ResourceGroupCreationFailed": "Failed to create the resource group. Error: %s", + "loc.messages.CreatingNewRG": "Creating resource Group: %s", + "loc.messages.CreatedRG": "Resource Group created successfully.", + "loc.messages.CreatingTemplateDeployment": "Creating deployment parameters.", + "loc.messages.TemplateParsingFailed": "Ensure the Template file ( '%s' ) is valid. Task failed while parsing with following error: %s", + "loc.messages.FileFetchFailed": "Failed to download the file. URL: '%s'. Error: %s", + "loc.messages.ParametersFileParsingFailed": "Ensure the Parameters file ( '%s' ) is valid. Task failed while parsing with following error: %s", + "loc.messages.StartingDeployment": "Starting Deployment.", + "loc.messages.CreateTemplateDeploymentSucceeded": "Successfully deployed the template.", + "loc.messages.CreateTemplateDeploymentFailed": "Task failed while creating or updating the template deployment.", + "loc.messages.ErrorsInYourDeployment": "There were errors in your deployment. Error code: %s.", + "loc.messages.Details": "Details:", + "loc.messages.ErrorType": "Error Type:", + "loc.messages.PolicyDefinitionName": "Policy Definition Name :", + "loc.messages.PolicyAssignmentName": "Policy Assignment Name :", + "loc.messages.StartingValidation": "Starting template validation.", + "loc.messages.ValidDeployment": "Template deployment validation was completed successfully.", + "loc.messages.CreateTemplateDeploymentValidationFailed": "Template validation failed. Error: %s.", + "loc.messages.DeletingResourceGroup": "Deleting resource group: %s", + "loc.messages.CouldNotDeletedResourceGroup": "Could not delete resource group: '%s'. Operation failed with error: %s", + "loc.messages.DeletedResourceGroup": "Deleted resource group: %s", + "loc.messages.InvalidAction": "This action is not defined. Check with the task author.", + "loc.messages.ARGD_ConstructorFailed": "Task failed while initializing. Error: %s", + "loc.messages.InvalidTemplateLocation": "The template location supplied is invalid. Task only supports 'Linked artifact' or 'URL of the file'", + "loc.messages.EncodingNotSupported": "Encoding of the file '%s' is '%s' which is not supported. Supported file encodings are ['utf-8', 'utf-16le']", + "loc.messages.CouldNotDetectEncoding": "Could not detect encoding of file '%s'", + "loc.messages.DetectedFileEncoding": "The detected encoding for file '%s' is '%s'", + "loc.messages.ErrorWhileParsingParameter": "There was an error while overriding '%s' parameter because of '%s', make sure it follows JavaScript Object Notation (JSON)", + "loc.messages.TemplateFilePatternMatchingMoreThanOneFile": "Found multiple files matching template file pattern: %s", + "loc.messages.TemplateParameterFilePatternMatchingMoreThanOneFile": "Found multiple files matching template parameters file pattern: %s", + "loc.messages.TemplateFilePatternMatchingNoFile": "Could not find any file matching the template file pattern", + "loc.messages.TemplateParameterFilePatternMatchingNoFile": "Could not find any file matching the template file pattern", + "loc.messages.ParametersPatternMatchesADirectoryInsteadOfAFile": "Parameters file pattern matches a directory instead of a file.", + "loc.messages.CsmFilePatternMatchesADirectoryInsteadOfAFile": "Template file pattern matches a directory instead of a file: %s", + "loc.messages.AddedOutputVariable": "Updated output variable '%s', which contains the outputs section of the current deployment object in string format.", + "loc.messages.UnableToReadResponseBody": "Unable to read response body. Error: %s", + "loc.messages.MoreInformationOnAzurePortal": "More information on Azure Portal", + "loc.messages.LogDeploymentName": "Deployment name is %s", + "loc.messages.ResourceGroupNameNotProvided": "Resource Group name should be provided", + "loc.messages.LocationNotProvided": "Location is required for deployment", + "loc.messages.ARMServiceConnectionScope": "ARM Service Conection deployment scope - %s" +} \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/CSM.json b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/CSM.json new file mode 100644 index 000000000000..8b9823e55ee7 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/CSM.json @@ -0,0 +1,8 @@ +{ + "parameters": { + "param": { + "value": false, + "toBeRemoved": true + } + } +} \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/CSMwithComments.json b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/CSMwithComments.json new file mode 100644 index 000000000000..786f77ba1304 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/CSMwithComments.json @@ -0,0 +1,5 @@ +{ + // This json file has comments + "var": "value ending with escaped character\\\"\\\\" + /*some Comment After the escaped Character */ +} \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/L0.ts b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/L0.ts new file mode 100644 index 000000000000..852692345283 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/L0.ts @@ -0,0 +1,176 @@ +'use strict'; + +const assert = require('assert'); +const ttm = require('azure-pipelines-task-lib/mock-test'); +const path = require('path'); + +function setResponseFile(name) { + process.env['MOCK_RESPONSES'] = path.join(__dirname, name); +} + +describe('Azure Resource Manager Template Deployment', function () { + this.timeout(30000); + before((done) => { + done(); + }); + after(function () { + }); + + process.env['AGENT_HOMEDIRECTORY'] = process.env['AGENT_HOMEDIRECTORY'] || "C:\\temp\\agent\\home"; + process.env['BUILD_SOURCESDIRECTORY'] = process.env['BUILD_SOURCESDIRECTORY'] || "C:\\temp\\agent\\home\\sources", + process.env['SYSTEM_DEFAULTWORKINGDIRECTORY'] = process.env['SYSTEM_DEFAULTWORKINGDIRECTORY'] || "C:\\temp\\agent\\home"; + process.env["AGENT_TEMPDIRECTORY"] = process.env["AGENT_TEMPDIRECTORY"] || "C:\\temp\\agent\\home\\temp"; + +// uncomment to get test traces +// process.env['TASK_TEST_TRACE'] = "1"; + + /*it('Successfully triggered createOrUpdate deployment', (done) => { + let tp = path.join(__dirname, 'createOrUpdate.js'); + process.env["csmFile"] = "CSM.json"; + process.env["csmParametersFile"] = "CSM.json"; + let tr = new ttm.MockTestRunner(tp); + tr.run(); + try { + assert(tr.succeeded, "Should have succeeded"); + assert(tr.stdout.indexOf("deployments.createOrUpdate is called") > 0, "deployments.createOrUpdate function should have been called from azure-sdk"); + assert(tr.stdout.indexOf("set ") < 0, "deploymentsOutput should not have been updated"); + assert(tr.stdout.indexOf("properly sanitized") > 0, "Parameters should have been sanitized"); + done(); + } + catch (error) { + console.log("STDERR", tr.stderr); + console.log("STDOUT", tr.stdout); + done(error); + } + });*/ + it('Successfully triggered createOrUpdate deployment and updated deploymentOutputs', (done) => { + let tp = path.join(__dirname, 'createOrUpdate.js'); + process.env["csmFile"] = "CSM.json"; + process.env["csmParametersFile"] = "CSM.json"; + process.env["deploymentOutputs"] = "someVar"; + let tr = new ttm.MockTestRunner(tp); + tr.run(); + try { + assert(tr.succeeded, "Should have succeeded"); + assert(tr.stdout.indexOf("properly sanitized") > 0, "Parameters should have been sanitized"); + assert(tr.stdout.indexOf("deployments.createOrUpdate is called") > 0, "deployments.createOrUpdate function should have been called from azure-sdk"); + assert(tr.stdout.indexOf("set someVar") >= 0, "deploymentsOutput should have been updated"); + done(); + } + catch (error) { + console.log("STDERR", tr.stderr); + console.log("STDOUT", tr.stdout); + done(error); + } + }); + it('Create or Update RG, failed on faulty CSM template file', (done) => { + let tp = path.join(__dirname, 'createOrUpdate.js'); + process.env["csmFile"] = "faultyCSM.json"; + process.env["csmParametersFile"] = "faultyCSM.json"; + let tr = new ttm.MockTestRunner(tp); + tr.run(); + try { + assert(tr.failed, "Task should have failed"); + assert(tr.stdout.indexOf("deployments.createOrUpdate is called") == -1, "Task should have failed before calling deployments.createOrUpdate function from azure-sdk"); + } + catch (error) { + console.log("STDERR", tr.stderr); + console.log("STDOUT", tr.stdout); + done(error); + } + done(); + }); + it('Create or Update RG, succeeded on CSM template file with comments', (done) => { + let tp = path.join(__dirname, 'createOrUpdate.js'); + process.env["csmFile"] = "CSMwithComments.json"; + process.env["csmParametersFile"] = "CSMwithComments.json"; + let tr = new ttm.MockTestRunner(tp); + tr.run(); + try { + assert(tr.succeeded, "Should have succeeded"); + assert(tr.stdout.indexOf("deployments.createOrUpdate is called") > 0, "deployments.createOrUpdate function should have been called from azure-sdk"); + done(); + } + catch (error) { + console.log("STDERR", tr.stderr); + console.log("STDOUT", tr.stdout); + done(error); + } + }); + it('createOrUpdate deployment should fail when no template file is found', (done) => { + let tp = path.join(__dirname, 'createOrUpdate.js'); + process.env["csmFile"] = "CSMNotThere.json"; + process.env["csmParametersFile"] = "CSM.json"; + let tr = new ttm.MockTestRunner(tp); + tr.run(); + try { + assert(!tr.succeeded, "Should have failed"); + assert(tr.stdout.indexOf("TemplateFilePatternMatchingNoFile") > 0, "should have printed TemplateFilePatternMatchingNoFile") + assert(tr.stdout.indexOf("deployments.createOrUpdate is called") < 0, "deployments.createOrUpdate function should not have been called from azure-sdk"); + done(); + } + catch (error) { + console.log("STDERR", tr.stderr); + console.log("STDOUT", tr.stdout); + done(error); + } + }); + + it('createOrUpdate deployment should fail when multiple template files are found', (done) => { + let tp = path.join(__dirname, 'createOrUpdate.js'); + process.env["csmFile"] = "CSMmultiple.json"; + process.env["csmParametersFile"] = "CSM.json"; + let tr = new ttm.MockTestRunner(tp); + tr.run(); + try { + assert(!tr.succeeded, "Should have failed"); + assert(tr.stdout.indexOf("TemplateFilePatternMatchingMoreThanOneFile") > 0, "should have printed TemplateFilePatternMatchingMoreThanOneFile") + assert(tr.stdout.indexOf("deployments.createOrUpdate is called") < 0, "deployments.createOrUpdate function should not have been called from azure-sdk"); + done(); + } + catch (error) { + console.log("STDERR", tr.stderr); + console.log("STDOUT", tr.stdout); + done(error); + } + }); + + it('createOrUpdate deployment should fail when no parameter file is found', (done) => { + let tp = path.join(__dirname, 'createOrUpdate.js'); + process.env["csmFile"] = "CSM.json"; + process.env["csmParametersFile"] = "CSMNotThere.json"; + let tr = new ttm.MockTestRunner(tp); + tr.run(); + try { + assert(!tr.succeeded, "Should have failed"); + assert(tr.stdout.indexOf("TemplateParameterFilePatternMatchingNoFile") > 0, "should have printed TemplateParameterFilePatternMatchingNoFile") + assert(tr.stdout.indexOf("deployments.createOrUpdate is called") < 0, "deployments.createOrUpdate function should not have been called from azure-sdk"); + done(); + } + catch (error) { + console.log("STDERR", tr.stderr); + console.log("STDOUT", tr.stdout); + done(error); + } + }); + + it('createOrUpdate deployment should fail when multiple template files are found', (done) => { + let tp = path.join(__dirname, 'createOrUpdate.js'); + process.env["csmFile"] = "CSM.json"; + process.env["csmParametersFile"] = "CSMmultiple.json"; + let tr = new ttm.MockTestRunner(tp); + tr.run(); + try { + assert(!tr.succeeded, "Should have failed"); + assert(tr.stdout.indexOf("TemplateParameterFilePatternMatchingMoreThanOneFile") > 0, "should have printed TemplateFilePatternMatchingMoreThanOneFile") + assert(tr.stdout.indexOf("deployments.createOrUpdate is called") < 0, "deployments.createOrUpdate function should not have been called from azure-sdk"); + done(); + } + catch (error) { + console.log("STDERR", tr.stderr); + console.log("STDOUT", tr.stdout); + done(error); + } + }); + +}); diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/createOrUpdate.ts b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/createOrUpdate.ts new file mode 100644 index 000000000000..b3c5a38a2038 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/createOrUpdate.ts @@ -0,0 +1,52 @@ +import ma = require('azure-pipelines-task-lib/mock-answer'); +import tmrm = require('azure-pipelines-task-lib/mock-run'); +import path = require('path'); + +let taskPath = path.join(__dirname, '..', 'main.js'); +let tr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath); + +tr.setInput("action", "Create Or Update Resource Group"); +tr.setInput("ConnectedServiceName", "AzureRM"); +tr.setInput("resourceGroupName", "dummy"); +tr.setInput("location", "West US"); +tr.setInput("templateLocation", "Linked artifact") +tr.setInput("csmFile", process.env["csmFile"]); +tr.setInput("overrideParameters", ""); +tr.setInput("deploymentMode", "Complete"); +tr.setInput("enableDeploymentPrerequisites", "None"); +tr.setInput("csmParametersFile", process.env["csmParametersFile"]); +tr.setInput("deploymentOutputs", !!process.env["deploymentOutputs"] ? process.env["deploymentOutputs"] : ""); + +process.env["ENDPOINT_AUTH_AzureRM"] = "{\"parameters\":{\"serviceprincipalid\":\"id\",\"serviceprincipalkey\":\"key\",\"tenantid\":\"tenant\"},\"scheme\":\"ServicePrincipal\"}"; +process.env["ENDPOINT_AUTH_PARAMETER_AzureRM_SERVICEPRINCIPALID"] = "id"; +process.env["ENDPOINT_AUTH_PARAMETER_AzureRM_SERVICEPRINCIPALKEY"] = "key"; +process.env["ENDPOINT_AUTH_PARAMETER_AzureRM_TENANTID"] = "tenant"; +process.env["ENDPOINT_DATA_AzureRM_SUBSCRIPTIONID"] = "sId"; +process.env["ENDPOINT_DATA_AzureRM_SUBSCRIPTIONNAME"] = "sName"; +process.env["ENDPOINT_URL_AzureRM"] = "https://management.azure.com/"; +process.env["ENDPOINT_DATA_AzureRM_ENVIRONMENTAUTHORITYURL"] = "https://login.windows.net/"; +process.env["ENDPOINT_DATA_AzureRM_ACTIVEDIRECTORYSERVICEENDPOINTRESOURCEID"] = "https://management.azure.com"; + +var CSMJson = path.join(__dirname, "CSM.json"); +var CSMwithComments = path.join(__dirname, "CSMwithComments.json"); +var defaults = path.join(__dirname, "defaults.json"); +var faultyCSM = path.join(__dirname, "faultyCSM.json"); + +let a: ma.TaskLibAnswers = { + "findMatch": { + "CSM.json": [CSMJson], + "CSMwithComments.json": [CSMwithComments], + "defaults.json": [defaults], + "faultyCSM.json": [faultyCSM], + "CSMNotThere.json": [], + "CSMmultiple.json": [CSMJson, CSMJson], + "": [""] + } +}; + +process.env["MOCK_NORMALIZE_SLASHES"] = "true"; +tr.setAnswers(a); + +tr.registerMock('azure-pipelines-task-lib/toolrunner', require('azure-pipelines-task-lib/mock-toolrunner')); +tr.registerMock('azure-arm-rest-v2/azure-arm-resource', require('./mock_node_modules/azure-arm-resource')); +tr.run(); \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/defaults.json b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/defaults.json new file mode 100644 index 000000000000..94c57135a556 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/defaults.json @@ -0,0 +1,10 @@ +{ + "getVariable": { + "ENDPOINT_AUTH_AzureRM": "{\"parameters\":{\"serviceprincipalid\":\"id\",\"serviceprincipalkey\":\"key\",\"tenantid\":\"tenant\"},\"scheme\":\"ServicePrincipal\"}", + "ENDPOINT_AUTH_PARAMETER_AzureRM_SERVICEPRINCIPALID": "id", + "ENDPOINT_AUTH_PARAMETER_AzureRM_SERVICEPRINCIPALKEY": "key", + "ENDPOINT_AUTH_PARAMETER_AzureRM_TENANTID": "tenant", + "ENDPOINT_DATA_AzureRM_SUBSCRIPTIONID": "sId", + "ENDPOINT_DATA_AzureRM_SUBSCRIPTIONNAME": "sName" + } +} \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/deleteResourceGroup.ts b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/deleteResourceGroup.ts new file mode 100644 index 000000000000..ffe869ac8547 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/deleteResourceGroup.ts @@ -0,0 +1,24 @@ +import ma = require('azure-pipelines-task-lib/mock-answer'); +import tmrm = require('azure-pipelines-task-lib/mock-run'); +import path = require('path'); + +let taskPath = path.join(__dirname, '..', 'main.js'); +let tr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath); + +tr.setInput("action", "DeleteRG"); +tr.setInput("ConnectedServiceName", "AzureRM"); +tr.setInput("resourceGroupName", "dummy"); + +process.env[ "ENDPOINT_AUTH_AzureRM"] = "{\"parameters\":{\"serviceprincipalid\":\"id\",\"serviceprincipalkey\":\"key\",\"tenantid\":\"tenant\"},\"scheme\":\"ServicePrincipal\"}"; +process.env["ENDPOINT_AUTH_PARAMETER_AzureRM_SERVICEPRINCIPALID"] = "id"; +process.env["ENDPOINT_AUTH_PARAMETER_AzureRM_SERVICEPRINCIPALKEY"] = "key"; +process.env["ENDPOINT_AUTH_PARAMETER_AzureRM_TENANTID"] = "tenant"; +process.env["ENDPOINT_DATA_AzureRM_SUBSCRIPTIONID"] = "sId"; +process.env["ENDPOINT_DATA_AzureRM_SUBSCRIPTIONNAME"] = "sName"; +process.env["ENDPOINT_URL_AzureRM"] = "https://management.azure.com/"; +process.env["ENDPOINT_DATA_AzureRM_ENVIRONMENTAUTHORITYURL"] = "https://login.windows.net/"; +process.env["ENDPOINT_DATA_AzureRM_ACTIVEDIRECTORYSERVICEENDPOINTRESOURCEID"] = "https://management.azure.com"; + +tr.registerMock('azure-pipelines-task-lib/toolrunner', require('azure-pipelines-task-lib/mock-toolrunner')); +tr.registerMock('azure-arm-rest-v2/azure-arm-resource', require('./mock_node_modules/azure-arm-resource')); +tr.run(); \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/faultyCSM.json b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/faultyCSM.json new file mode 100644 index 000000000000..8bb8e97c3c03 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/faultyCSM.json @@ -0,0 +1,3 @@ +{ + "parameters" +} \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/LICENSE.txt b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/LICENSE.txt new file mode 100644 index 000000000000..a28827c2b848 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Microsoft + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/README.md b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/README.md new file mode 100644 index 000000000000..1e5d74dd51ed --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/README.md @@ -0,0 +1,147 @@ +# Microsoft Azure SDK for Node.js - Resource Management + +This project provides a Node.js package that makes it easy to manage Azure resources. Right now it supports: +- **Node.js version: 4.x.x or higher** +- **API version: 2016-02-01** + +## Features + + - TODO + +## How to Install + +```bash +npm install azure-arm-resource +``` + +## How to Use + +### Authentication, client creation and listing resources as an example + + ```javascript + var msRestAzure = require('ms-rest-azure'); + var resourceManagement = require("azure-arm-resource"); + + // Interactive Login + msRestAzure.interactiveLogin(function(err, credentials) { + var client = new resourceManagement.ResourceManagementClient(credentials, groupName, 'your-subscription-id'); + client.resources.list(function(err, result) { + if (err) console.log(err); + console.log(result); + }); + }); + ``` + +## Creating a Resource Group + +```javascript +var util = require('util'); +var groupParameters = { + location: 'West US', + tags: { + tag1: 'val1', + tag2: 'val2' + } +}; +client.resourceGroup.createOrUpdate(groupParameters, function (err, result, request, response) { + if (err) { + console.log(err); + /*err has reference to the actual request and response, so you can see what was sent and received on the wire. + The structure of err looks like this: + err: { + code: 'Error Code', + message: 'Error Message', + body: 'The response body if any', + request: reference to a stripped version of http request + response: reference to a stripped version of the response + } + */ + } else { + console.log('result is: ' + util.inspect(result, {depth: null})); + } +}); +``` + +## Create a Generic Resource in a Resource Group + +```javascript +var resourceName = 'autorestsite102'; +var params = { 'location': 'West US', 'properties' : { 'SiteMode': 'Limited', 'ComputeMode': 'Shared' }, 'Name': resourceName }; +var resourceType = 'sites'; +var parentResourcePath = ''; +var resourceProviderNamespace = 'Microsoft.Web'; +var apiVersion = '2014-04-01'; +client.resources.createOrUpdate(, parentResourcePath, + resourceType, resourceName , apiVersion, params, function (err, result, request, response) { + if (err) { + console.log(err); + } else { + console.log(result); + } +}); +``` + +## Get a Generic Resource in a Resource Group + +```javascript +var resourceName = 'autorestsite102'; +var resourceType = 'sites'; +var parentResourcePath = ''; +var resourceProviderNamespace = 'Microsoft.Web'; +var apiVersion = '2014-04-01'; +client.resources.get(resourceProviderNamespace, parentResourcePath, + resourceType, resourceName, apiVersion, function (err, result, request, response) { + if (err) { + console.log(err); + } else { + console.log(result); + } +}); +``` + +## Listing all resources in your subscription + +```javascript +client.resources.list(function (err, result, request, response) { + if (err) { + console.log(err); + } else { + console.log(result); + } +}); +``` + +## Deleting a Generic Resource in a Resource Group + +```javascript +var resourceName = 'autorestsite102'; +var resourceType = 'sites'; +var parentResourcePath = ''; +var resourceProviderNamespace = 'Microsoft.Web'; +var apiVersion = '2014-04-01'; +client.resources.deleteMethod(resourceProviderNamespace, parentResourcePath, + resourceType, resourceName, apiVersion, function (err, result, request, response) { + if (err) { + console.log(err); + } else { + console.log(result); + } +}); +``` + +## Deleting the Resource Group + +```javascript +client.resourceGroup.deleteMethod(function (err, result, request, response) { + if (err) { + console.log(err); + } else { + console.log(result); + } +}); +``` +Please take a look at the tests over [here](https://github.com/Azure/azure-sdk-for-node/tree/autorest/test/services/resourceManagement) for more examples. + +## Related projects + +- [Microsoft Azure SDK for Node.js - All-up](https://github.com/Azure/azure-sdk-for-node) diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource.js b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource.js new file mode 100644 index 000000000000..454f46b21f40 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource.js @@ -0,0 +1,20 @@ +// +// Copyright (c) Microsoft and contributors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// +'use strict'; + +exports.ResourceManagementClient = require('./resource/resourceManagementClient'); + +exports = module.exports; \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource/operations/index.js b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource/operations/index.js new file mode 100644 index 000000000000..e7b9d2093baa --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource/operations/index.js @@ -0,0 +1,18 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +/* jshint latedef:false */ +/* jshint forin:false */ +/* jshint noempty:false */ + +'use strict'; + +exports.ResourceGroupDeployments = require('./resourceGroupDeployments'); +exports.ResourceGroup = require('./resourceGroup'); diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource/operations/resourceGroup.js b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource/operations/resourceGroup.js new file mode 100644 index 000000000000..ecbcb9023831 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource/operations/resourceGroup.js @@ -0,0 +1,87 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +'use strict'; + +var util = require('util'); + +/** + * @class + * ResourceGroup + * __NOTE__: An instance of this class is automatically created for an + * instance of the ResourceManagementClient. + * Initializes a new instance of the ResourceGroup class. + * @constructor + * + * @param {ResourceManagementClient} client Reference to the service client. + */ +function ResourceGroup(client) { + this.client = client; +} + +ResourceGroup.prototype.createOrUpdate = function (parameters, callback) { + console.log("resourceGroup.createOrUpdate is called") + var client = this.client; + if (!callback) { + throw new Error('callback cannot be null.'); + } + // Validate + try { + if (client.resourceGroupName === null || client.resourceGroupName === undefined || typeof client.resourceGroupName.valueOf() !== 'string') { + throw new Error('client.resourceGroupName cannot be null or undefined and it must be of type string.'); + } + if (client.resourceGroupName !== null && client.resourceGroupName !== undefined) { + if (client.resourceGroupName.length > 90) + { + throw new Error('"client.resourceGroupName" should satisfy the constraint - "MaxLength": 90'); + } + if (client.resourceGroupName.length < 1) + { + throw new Error('"client.resourceGroupName" should satisfy the constraint - "MinLength": 1'); + } + if (client.resourceGroupName.match(/^[-\w\._\(\)]+$/) === null) + { + throw new Error('"client.resourceGroupName" should satisfy the constraint - "Pattern": /^[-\w\._\(\)]+$/'); + } + } + if (parameters === null || parameters === undefined) { + throw new Error('parameters cannot be null or undefined.'); + } + if (this.client.apiVersion === null || this.client.apiVersion === undefined || typeof this.client.apiVersion.valueOf() !== 'string') { + throw new Error('this.client.apiVersion cannot be null or undefined and it must be of type string.'); + } + if (this.client.subscriptionId === null || this.client.subscriptionId === undefined || typeof this.client.subscriptionId.valueOf() !== 'string') { + throw new Error('this.client.subscriptionId cannot be null or undefined and it must be of type string.'); + } + if (this.client.acceptLanguage !== null && this.client.acceptLanguage !== undefined && typeof this.client.acceptLanguage.valueOf() !== 'string') { + throw new Error('this.client.acceptLanguage must be of type string.'); + } + } catch (error) { + return callback(error); + } + callback(null, true); +}; + +ResourceGroup.prototype.deleteMethod = function (callback) { + console.log("resourceGroup.deleteMethod is called") + var client = this.client; + + if (!callback) { + throw new Error('callback cannot be null.'); + } + +}; + +ResourceGroup.prototype.checkExistence = function (callback) { + console.log("resourceGroup.checkExistence is called") + return callback(null, true); +} + +module.exports = ResourceGroup; diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource/operations/resourceGroupDeployments.js b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource/operations/resourceGroupDeployments.js new file mode 100644 index 000000000000..ce19d5ace71c --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource/operations/resourceGroupDeployments.js @@ -0,0 +1,37 @@ +'use strict'; + +var util = require('util'); + +function ResourceGroupDeployments(client) { + this.client = client; +} + +ResourceGroupDeployments.prototype.createOrUpdate = function (deploymentName, parameters, callback) { + console.log("deployments.createOrUpdate is called") + + if (!callback && typeof options === 'function') { + callback = options; + options = null; + } + console.log(JSON.stringify(parameters)); + if (!!parameters["properties"] && !!parameters["properties"]["parameters"] && !!parameters["properties"]["parameters"]["param"]) { + if (!!parameters["properties"]["parameters"]["param"]["toBeRemoved"]) { + console.log("not sanitized"); + } + else { + console.log("properly sanitized"); + } + } + + if (!callback) { + throw new Error('callback cannot be null.'); + } + return callback(null, { + properties: { + outputs: {} + } + }) +}; + + +module.exports = ResourceGroupDeployments; diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource/resourceManagementClient.js b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource/resourceManagementClient.js new file mode 100644 index 000000000000..ba61d7574010 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/lib/resource/resourceManagementClient.js @@ -0,0 +1,45 @@ + +'use strict'; + +var util = require('util'); + +var operations = require('./operations'); +function ResourceManagementClient(credentials, resourceGroupName, subscriptionId, baseUri, options) { + this.apiVersion = '2016-07-01'; + this.acceptLanguage = 'en-US'; + this.longRunningOperationRetryTimeout = 30; + this.generateClientRequestId = true; + if (credentials === null || credentials === undefined) { + throw new Error('\'credentials\' cannot be null.'); + } + if (subscriptionId === null || subscriptionId === undefined) { + throw new Error('\'subscriptionId\' cannot be null.'); + } + if (!options) options = {}; + + this.baseUri = baseUri; + if (!this.baseUri) { + this.baseUri = 'https://management.azure.com'; + } + this.credentials = credentials; + this.subscriptionId = subscriptionId; + + if (options.apiVersion !== null && options.apiVersion !== undefined) { + this.apiVersion = options.apiVersion; + } + if (options.acceptLanguage !== null && options.acceptLanguage !== undefined) { + this.acceptLanguage = options.acceptLanguage; + } + if (options.longRunningOperationRetryTimeout !== null && options.longRunningOperationRetryTimeout !== undefined) { + this.longRunningOperationRetryTimeout = options.longRunningOperationRetryTimeout; + } + if (options.generateClientRequestId !== null && options.generateClientRequestId !== undefined) { + this.generateClientRequestId = options.generateClientRequestId; + } + this.deployments = new operations.ResourceGroupDeployments(this); + this.resourceGroup = new operations.ResourceGroup(this); + this.resourceGroupName = resourceGroupName; +} + + +module.exports = ResourceManagementClient; diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/package.json b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/package.json new file mode 100644 index 000000000000..31f81ceb3e5a --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/mock_node_modules/azure-arm-resource/package.json @@ -0,0 +1,108 @@ +{ + "_args": [ + [ + { + "raw": "azure-arm-resource@1.5.1-preview", + "scope": null, + "escapedName": "azure-arm-resource", + "name": "azure-arm-resource", + "rawSpec": "1.5.1-preview", + "spec": "1.5.1-preview", + "type": "version" + }, + "D:\\git\\vsts-tasks\\Tasks\\DeployAzureResourceGroup" + ] + ], + "_from": "azure-arm-resource@1.5.1-preview", + "_id": "azure-arm-resource@1.5.1-preview", + "_inCache": true, + "_installable": true, + "_location": "/azure-arm-resource", + "_nodeVersion": "4.4.7", + "_npmOperationalInternal": { + "host": "packages-16-east.internal.npmjs.com", + "tmp": "tmp/azure-arm-resource-1.5.1-preview.tgz_1472854031051_0.035985670518130064" + }, + "_npmUser": { + "name": "windowsazure", + "email": "azuresdk@outlook.com" + }, + "_npmVersion": "3.10.5", + "_phantomChildren": {}, + "_requested": { + "raw": "azure-arm-resource@1.5.1-preview", + "scope": null, + "escapedName": "azure-arm-resource", + "name": "azure-arm-resource", + "rawSpec": "1.5.1-preview", + "spec": "1.5.1-preview", + "type": "version" + }, + "_requiredBy": [ + "#DEV:/" + ], + "_resolved": "https://registry.npmjs.org/azure-arm-resource/-/azure-arm-resource-1.5.1-preview.tgz", + "_shasum": "2f8666289f24927aa08331e60d368b11474cf68e", + "_shrinkwrap": null, + "_spec": "azure-arm-resource@1.5.1-preview", + "_where": "D:\\git\\vsts-tasks\\Tasks\\DeployAzureResourceGroup", + "author": { + "name": "Microsoft Corporation" + }, + "bugs": { + "url": "http://github.com/Azure/azure-sdk-for-node/issues" + }, + "contributors": [ + { + "name": "Wang, Yugang", + "email": "yugangw@microsoft.com" + }, + { + "name": "Zavery, Amar", + "email": "amzavery@microsoft.com" + }, + { + "name": "Srinivasan, Vivek", + "email": "visriniv@microsoft.com" + } + ], + "dependencies": { + "ms-rest": "^1.14.0", + "ms-rest-azure": "^1.14.0" + }, + "description": "Microsoft Azure Resource Management Client Library for node", + "devDependencies": {}, + "directories": {}, + "dist": { + "shasum": "2f8666289f24927aa08331e60d368b11474cf68e", + "tarball": "https://registry.npmjs.org/azure-arm-resource/-/azure-arm-resource-1.5.1-preview.tgz" + }, + "homepage": "http://github.com/Azure/azure-sdk-for-node", + "keywords": [ + "node", + "azure" + ], + "license": "MIT", + "main": "./lib/resource.js", + "maintainers": [ + { + "name": "windowsazure", + "email": "azuresdk@outlook.com" + } + ], + "name": "azure-arm-resource", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/Azure/azure-sdk-for-node.git" + }, + "scripts": { + "test": "npm -s run-script jshint" + }, + "tags": [ + "azure", + "sdk" + ], + "version": "1.5.1-preview" +} diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/ThirdPartyNotices.txt b/Tasks/AzureResourceManagerTemplateDeploymentV3/ThirdPartyNotices.txt new file mode 100644 index 000000000000..40df19c248e4 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/ThirdPartyNotices.txt @@ -0,0 +1,1138 @@ + +THIRD-PARTY SOFTWARE NOTICES AND INFORMATION +Do Not Translate or Localize + +Azure Resource Management Template Deployment Task incorporates third party material from the projects listed below. The original copyright notice and the license under which Microsoft received such third party material are set forth below. Microsoft reserves all other rights not expressly granted, whether by implication, estoppel or otherwise. + + +1. balanced-match (https://github.com/juliangruber/balanced-match) +2. brace-expansion (https://github.com/juliangruber/brace-expansion) +3. buffer-equal-constant-time (https://github.com/salesforce/buffer-equal-constant-time) +4. concat-map (https://github.com/substack/node-concat-map) +5. hoek (https://github.com/hapijs/hoek) + Includes:Deep-eql +6. isemail (https://github.com/hapijs/isemail) +7. joi (https://github.com/hapijs/joi) +8. jsonwebtoken (https://github.com/auth0/node-jsonwebtoken) +9. lodash.once (https://github.com/lodash/lodash) +10. minimatch (https://github.com/isaacs/minimatch) +11. Mockery (https://github.com/mfncooper/mockery) +12. Moment (https://github.com/moment/moment) + Includes:Files with code from Closure +13. ms (https://github.com/zeit/ms) +14. Node.js (https://nodejs.org/) +15. node-ecdsa-sig-formatter (https://github.com/Brightspace/node-ecdsa-sig-formatter) +16. node-jwa (https://github.com/brianloveswords/node-jwa) +17. node-jws (https://github.com/brianloveswords/node-jws) +18. node-uuid (https://github.com/broofa/node-uuid/) +19. OpenSSL (http://www.openssl.org) +20. Q (https://github.com/kriskowal/q) +21. safe-buffer (https://github.com/feross/safe-buffer) +22. sax js (https://github.com/isaacs/sax-js) +23. semver (https://github.com/npm/node-semver/) +24. ShellJS (https://github.com/shelljs/shelljs) +25. topo (https://github.com/hapijs/topo) +26. tunnel (https://github.com/koichik/node-tunnel) +27. underscore.js (http://underscorejs.org/; https://github.com/jashkenas/underscore) +28. vso-node-api (https://github.com/Microsoft/vsts-node-api) +29. azure-pipelines-task-lib (https://github.com/Microsoft/azure-pipelines-task-lib) +30. Xml2JS (https://github.com/Leonidas-from-XIV/node-xml2js) +31. Xmlbuilder (https://github.com/oozcitak/xmlbuilder-js) +32. xtend (https://github.com/Raynos/xtend) +33. @types/node (https://www.github.com/DefinitelyTyped/DefinitelyTyped.git) +34. @types/q (https://www.github.com/DefinitelyTyped/DefinitelyTyped.git) +35. @types/mocha (https://github.com/DefinitelyTyped/DefinitelyTyped.git) + + +%% balanced-match NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +(MIT) + +Copyright (c) 2013 Julian Gruber + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========================================= +END OF balanced-match NOTICES, INFORMATION, AND LICENSE + +%% brace-expansion NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +(MIT) + +Copyright (c) 2013 Julian Gruber + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========================================= +END OF brace-expansion NOTICES, INFORMATION, AND LICENSE + +%% buffer-equal-constant-time NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright (c) 2013, GoInstant Inc., a salesforce.com company +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +* Neither the name of salesforce.com, nor GoInstant, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +========================================= +END OF buffer-equal-constant-time NOTICES, INFORMATION, AND LICENSE + +%% concat-map NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright (c) James Halliday/substack + +This software is released under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF concat-map NOTICES, INFORMATION, AND LICENSE + +%% hoek NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= + +Copyright (c) 2011-2014, Walmart and other contributors. +Copyright (c) 2011, Yahoo Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * The names of any contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * * * + +The complete list of contributors can be found at: https://github.com/hapijs/hapi/graphs/contributors +Portions of this project were initially based on the Yahoo! Inc. Postmile project, +published at https://github.com/yahoo/postmile. +========================================= +Includes code from Deep-eql + +Copyright (c) 2013 Jake Luer jake@alogicalparadox.com + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF hoek NOTICES, INFORMATION, AND LICENSE + +%% isemail NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright (c) 2008-2011, Dominic Sayers +Copyright (c) 2013-2014, GlobeSherpa +Copyright (c) 2014-2015, Eli Skeggs + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +- Neither the name of Dominic Sayers nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +========================================= +END OF isemail NOTICES, INFORMATION, AND LICENSE + +%% joi NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright (c) 2012-2014, Walmart and other contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * The names of any contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * * * + +The complete list of contributors can be found at: https://github.com/hapijs/joi/graphs/contributors +========================================= +END OF joi NOTICES, INFORMATION, AND LICENSE + +%% jsonwebtoken NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2015 Auth0, Inc. (http://auth0.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +========================================= +END OF jsonwebtoken NOTICES, INFORMATION, AND LICENSE + +%% lodash.once NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. +========================================= +END OF lodash.once NOTICES, INFORMATION, AND LICENSE + +%% minimatch NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +========================================= +END OF minimatch NOTICES, INFORMATION, AND LICENSE + +%% Mockery NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyrights for code authored by Yahoo! Inc. is licensed under the following +terms: + + MIT License + + Copyright (c) 2011 Yahoo! Inc. All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +========================================= +END OF Mockery NOTICES, INFORMATION, AND LICENSE + +%% Moment NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright (c) JS Foundation and other contributors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +========================================= +Files with code from Closure + +Copyright (c) 2006 The Closure Library Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +========================================= +END OF Moment NOTICES, INFORMATION, AND LICENSE + +%% ms NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +(The MIT License) + +Copyright (c) 2014 Guillermo Rauch +Copyright (c) 2016 Zeit, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the Software), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF ms NOTICES, INFORMATION, AND LICENSE + +%% Node.js NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +The Node.js license applies to all parts of Node.js that are not externally +maintained libraries. +========================================= +END OF Node.js NOTICES, INFORMATION, AND LICENSE + +%% node-ecdsa-sig-formatter NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= + Copyright 2015 D2L Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +========================================= +END OF node-ecdsa-sig-formatter NOTICES, INFORMATION, AND LICENSE + +%% node-jwa NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright (c) 2013 Brian J. Brennan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF node-jwa NOTICES, INFORMATION, AND LICENSE + +%% node-jws NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright (c) 2013 Brian J. Brennan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF node-jws NOTICES, INFORMATION, AND LICENSE + +%% node-uuid NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2010-2012 Robert Kieffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Software), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF node-uuid NOTICES, INFORMATION, AND LICENSE + +%% OpenSSL NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= + LICENSE ISSUES + ============== + + The OpenSSL toolkit stays under a dual license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. Actually both licenses are BSD-style + Open Source licenses. In case of any license issues related to OpenSSL + please contact openssl-core@openssl.org. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/) + * + * 4. The names OpenSSL Toolkit and OpenSSL Project must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called OpenSSL + * nor may OpenSSL appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/) + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com) + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * This product includes software written by Tim Hudson (tjh@cryptsoft.com) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] +========================================= +END OF OpenSSL NOTICES, INFORMATION, AND LICENSE + +%% Q NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright 2009�2014 Kristopher Michael Kowal. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +The file q.js is prefaced by the following additional third-party subcomponent information: + +/*! + * + * Copyright 2009-2012 Kris Kowal under the terms of the MIT + * license found at http://github.com/kriskowal/q/raw/master/LICENSE + * + * With parts by Tyler Close + * Copyright 2007-2009 Tyler Close under the terms of the MIT X license found + * at http://www.opensource.org/licenses/mit-license.html + * Forked at ref_send.js version: 2009-05-11 + * + * With parts by Mark Miller + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +========================================= +END OF Q NOTICES, INFORMATION, AND LICENSE + +%% safe-buffer NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) Feross Aboukhadijeh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF safe-buffer NOTICES, INFORMATION, AND LICENSE + +%% sax js NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +==== + +`String.fromCodePoint` by Mathias Bynens used according to terms of MIT +License, as follows: + + Copyright Mathias Bynens + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF sax js NOTICES, INFORMATION, AND LICENSE + +%% semver NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +========================================= +END OF semver NOTICES, INFORMATION, AND LICENSE + +%% ShellJS NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright (c) 2012, Artur Adib +All rights reserved. + +You may use this project under the terms of the New BSD license as follows: + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Artur Adib nor the + names of the contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL ARTUR ADIB BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +========================================= +END OF ShellJS NOTICES, INFORMATION, AND LICENSE + +%% topo NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright (c) 2012-2014, Walmart and other contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * The names of any contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * * * + +The complete list of contributors can be found at: https://github.com/hapijs/topo/graphs/contributors +========================================= +END OF topo NOTICES, INFORMATION, AND LICENSE + +%% tunnel NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2012 Koichi Kobayashi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF tunnel NOTICES, INFORMATION, AND LICENSE + +%% underscore.js NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright (c) 2009-2017 Jeremy Ashkenas, DocumentCloud and Investigative +Reporters & Editors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +========================================= +END OF underscore.js NOTICES, INFORMATION, AND LICENSE + +%% vso-node-api NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright (c) Microsoft Corporation + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF vso-node-api NOTICES, INFORMATION, AND LICENSE + +%% azure-pipelines-task-lib NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) Microsoft Corporation. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +========================================= +END OF azure-pipelines-task-lib NOTICES, INFORMATION, AND LICENSE + +%% Xml2JS NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright 2010, 2011, 2012, 2013. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +========================================= +END OF Xml2JS NOTICES, INFORMATION, AND LICENSE + +%% Xmlbuilder NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2013 Ozgur Ozcitak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF Xmlbuilder NOTICES, INFORMATION, AND LICENSE + +%% xtend NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Copyright (c) 2012-2014 Raynos. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the Software), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF xtend NOTICES, INFORMATION, AND LICENSE + +%% @types/mocha NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) Microsoft Corporation. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF @types/mocha NOTICES, INFORMATION, AND LICENSE + +%% @types/node NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF @types/node NOTICES, INFORMATION, AND LICENSE + +%% @types/q NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF @types/q NOTICES, INFORMATION, AND LICENSE \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/icon.png b/Tasks/AzureResourceManagerTemplateDeploymentV3/icon.png new file mode 100644 index 000000000000..c06715f15bbe Binary files /dev/null and b/Tasks/AzureResourceManagerTemplateDeploymentV3/icon.png differ diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/icon.svg b/Tasks/AzureResourceManagerTemplateDeploymentV3/icon.svg new file mode 100644 index 000000000000..179725f3182c --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/main.ts b/Tasks/AzureResourceManagerTemplateDeploymentV3/main.ts new file mode 100644 index 000000000000..542fa936b602 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/main.ts @@ -0,0 +1,60 @@ +import tl = require("azure-pipelines-task-lib/task"); +import path = require("path"); + +import armDeployTaskParameters = require("./models/TaskParameters"); +import resourceGroup = require("./operations/ResourceGroup"); +import armResource = require("azure-arm-rest-v2/azure-arm-resource"); +import armManagementGroup = require("azure-arm-rest-v2/azure-arm-management-group"); +import armSubscription = require("azure-arm-rest-v2/azure-arm-subscription"); +import { DeploymentParameters } from "./operations/DeploymentParameters"; +import { DeploymentScopeBase } from "./operations/DeploymentScopeBase"; + +function run(): Promise { + var taskParameters = new armDeployTaskParameters.TaskParameters(); + return taskParameters.getTaskParameters().then((taskParameters) => { + if(taskParameters.deploymentScope === "Management Group"){ + var deploymentParameters = new DeploymentParameters({}, taskParameters.location); + var managementGroupOperationsController = new DeploymentScopeBase( + new armManagementGroup.ManagementGroupManagementClient( + taskParameters.credentials, + taskParameters.managementGroupId), + taskParameters, + deploymentParameters); + return managementGroupOperationsController.deploy(); + } + else if(taskParameters.deploymentScope === "Subscription") { + var deploymentParameters = new DeploymentParameters({}, taskParameters.location); + var subscriptionOperationsController = new DeploymentScopeBase( + new armSubscription.SubscriptionManagementClient( + taskParameters.credentials, + taskParameters.subscriptionId), + taskParameters, + deploymentParameters); + return subscriptionOperationsController.deploy(); + } + var resourceGroupOperationsController = new resourceGroup.ResourceGroup( + new armResource.ResourceManagementClient( + taskParameters.credentials, + taskParameters.resourceGroupName, + taskParameters.subscriptionId), + taskParameters); + switch (taskParameters.action) { + case "Create Or Update Resource Group": + return resourceGroupOperationsController.deploy(); + case "DeleteRG": + return resourceGroupOperationsController.deleteResourceGroup(); + default: + throw tl.loc("InvalidAction", taskParameters.action); + } + }); +} + +var taskManifestPath = path.join(__dirname, "task.json"); +tl.debug("Setting resource path to " + taskManifestPath); +tl.setResourcePath(taskManifestPath); + +run().then((result) => + tl.setResult(tl.TaskResult.Succeeded, "") +).catch((error) => + tl.setResult(tl.TaskResult.Failed, error) +); diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/make.json b/Tasks/AzureResourceManagerTemplateDeploymentV3/make.json new file mode 100644 index 000000000000..8234391352ef --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/make.json @@ -0,0 +1,19 @@ +{ + "common": [ + { + "module": "../Common/azure-arm-rest-v2", + "type": "node", + "dest": "./", + "compile": true + } + ], + "rm": [ + { + "items": [ + "node_modules/azure-arm-rest-v2/node_modules/azure-pipelines-task-lib", + "node_modules/azure-arm-rest-v2/node_modules/vso-node-api" + ], + "options": "-Rf" + } + ] +} \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/models/TaskParameters.ts b/Tasks/AzureResourceManagerTemplateDeploymentV3/models/TaskParameters.ts new file mode 100644 index 000000000000..d0c9072c22f9 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/models/TaskParameters.ts @@ -0,0 +1,112 @@ +import tl = require("azure-pipelines-task-lib/task"); +import msRestAzure = require('azure-arm-rest-v2/azure-arm-common'); +import { AzureRMEndpoint } from 'azure-arm-rest-v2/azure-arm-endpoint'; + +export class TaskParameters { + + public action: string; + public resourceGroupName: string; + public location: string; + public csmFile: string; + public csmParametersFile: string; + public templateLocation: string; + public csmFileLink: string; + public csmParametersFileLink: string; + public overrideParameters: string; + public outputVariable: string; + public subscriptionId: string; + public endpointPortalUrl: string; + public deploymentName: string; + public deploymentMode: string; + public credentials: msRestAzure.ApplicationTokenCredentials; + public deploymentOutputs: string; + public addSpnToEnvironment: boolean; + public connectedService: string; + public deploymentScope: string; + public managementGroupId: string; + + private async getARMCredentials(connectedService: string): Promise { + var azureEndpoint = await new AzureRMEndpoint(connectedService).getEndpoint(); + return azureEndpoint.applicationTokenCredentials; + } + + public async getTaskParameters() : Promise + { + try { + + //Deployment Scope + this.deploymentScope = tl.getInput("deploymentScope"); + if(!this.deploymentScope){ + this.deploymentScope = "Resource Group"; + } + + var resourceGroupNameInServiceConnection; + + //Service Connection + this.connectedService = tl.getInput("ConnectedServiceName", true); + var endpointTelemetry = '{"endpointId":"' + this.connectedService + '"}'; + console.log("##vso[telemetry.publish area=TaskEndpointId;feature=AzureResourceManagerTemplateDeployment]" + endpointTelemetry); + this.endpointPortalUrl = tl.getEndpointDataParameter(this.connectedService, "armManagementPortalUrl", true); + var armServiceConnectionScope = tl.getEndpointDataParameter(this.connectedService, 'ScopeLevel', true); + if(!!armServiceConnectionScope && armServiceConnectionScope === "Subscription"){ + var armServiceConnectionAuthScope = tl.getEndpointAuthorizationParameter(this.connectedService, 'scope', true); + if(!!armServiceConnectionAuthScope){ + var armServiceConnectionAuthScopeSplit = armServiceConnectionAuthScope.split("/"); + if(!!armServiceConnectionAuthScopeSplit[4]){ + armServiceConnectionScope = "Resource Group"; + resourceGroupNameInServiceConnection = armServiceConnectionAuthScopeSplit[4]; + } + } + } + console.log(tl.loc("ARMServiceConnectionScope", armServiceConnectionScope)); + + //Management Group Id + if(this.deploymentScope === "Management Group"){ + this.managementGroupId = tl.getEndpointDataParameter(this.connectedService, "ManagementGroupId", false); + } + + //Subscripion Id + this.subscriptionId = tl.getInput("subscriptionName"); + if(!this.subscriptionId && (this.deploymentScope === "Subscription" || this.deploymentScope === "Resource Group")) { + this.subscriptionId = tl.getEndpointDataParameter(this.connectedService, "SubscriptionId", false); + } + + //Resource group name + this.resourceGroupName = tl.getInput("resourceGroupName"); + if(!this.resourceGroupName && this.deploymentScope === "Resource Group"){ + this.resourceGroupName = resourceGroupNameInServiceConnection; + if(!this.resourceGroupName){ + throw new Error(tl.loc("ResourceGroupNameNotProvided")); + } + } + + //Location + this.location = tl.getInput("location"); + if(!this.location && this.deploymentScope === "Resource Group" && this.action != "DeleteRG"){ + throw new Error(tl.loc("LocationNotProvided")); + } + + + this.templateLocation = tl.getInput("templateLocation"); + if (this.templateLocation === "Linked artifact") { + this.csmFile = tl.getPathInput("csmFile"); + this.csmParametersFile = tl.getPathInput("csmParametersFile"); + } else { + this.csmFileLink = tl.getInput("csmFileLink"); + this.csmParametersFileLink = tl.getInput("csmParametersFileLink"); + } + this.overrideParameters = tl.getInput("overrideParameters"); + this.outputVariable = tl.getInput("outputVariable"); + this.deploymentName = tl.getInput("deploymentName"); + this.deploymentMode = tl.getInput("deploymentMode"); + this.credentials = await this.getARMCredentials(this.connectedService); + this.deploymentOutputs = tl.getInput("deploymentOutputs"); + this.addSpnToEnvironment = tl.getBoolInput("addSpnToEnvironment", false); + this.action = tl.getInput("action"); + + return this; + } catch (error) { + throw new Error(tl.loc("ARGD_ConstructorFailed", error.message)); + } + } +} diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/models/Types.ts b/Tasks/AzureResourceManagerTemplateDeploymentV3/models/Types.ts new file mode 100644 index 000000000000..dddc60ba1ed7 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/models/Types.ts @@ -0,0 +1,14 @@ +export interface ParameterValue { + value?: any; + reference?: any; + type?: string; +} + +export interface TemplateObject { + $schema: string; + contentVersion: string; + outputs: Map; + parameters: Map; + resources: Map[]; + variables: Map; +} \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/DeploymentParameters.ts b/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/DeploymentParameters.ts new file mode 100644 index 000000000000..7010c8c25b19 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/DeploymentParameters.ts @@ -0,0 +1,13 @@ +export class DeploymentParameters { + public properties: Object; + public location: string; + + constructor(properties: Object, location?: string) { + this.properties = properties; + this.location = location; + } + public updateCommonProperties(mode: string) { + this.properties["mode"] = mode; + this.properties["debugSetting"] = { "detailLevel": "requestContent, responseContent" }; + } +} diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/DeploymentScopeBase.ts b/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/DeploymentScopeBase.ts new file mode 100644 index 000000000000..cea703730fec --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/DeploymentScopeBase.ts @@ -0,0 +1,96 @@ +import tl = require("azure-pipelines-task-lib/task"); + +import armDeployTaskParameters = require("../models/TaskParameters"); +import armResource = require("azure-arm-rest-v2/AzureServiceClientBase"); +import utils = require("./Utils"); +import { sleepFor } from 'azure-arm-rest-v2/webClient'; +import { DeploymentParameters } from "./DeploymentParameters"; + +export class DeploymentScopeBase { + protected deploymentParameters: DeploymentParameters; + protected taskParameters: armDeployTaskParameters.TaskParameters; + protected armClient: armResource.AzureServiceClientBase; + + constructor(armClient: armResource.AzureServiceClientBase, taskParameters: armDeployTaskParameters.TaskParameters, deploymentParameters?: DeploymentParameters) { + this.taskParameters = taskParameters; + this.armClient = armClient; + this.deploymentParameters = deploymentParameters; + } + + public async deploy(): Promise { + await this.createTemplateDeployment(); + } + + protected async createTemplateDeployment() { + console.log(tl.loc("CreatingTemplateDeployment")); + var params: DeploymentParameters; + if (this.taskParameters.templateLocation === "Linked artifact") { + params = utils.getDeploymentDataForLinkedArtifact(this.taskParameters); + } else if (this.taskParameters.templateLocation === "URL of the file") { + params = await utils.getDeploymentObjectForPublicURL(this.taskParameters); + } else { + throw new Error(tl.loc("InvalidTemplateLocation")); + } + + if(!!this.deploymentParameters){ + params.location = this.deploymentParameters.location; + } + + this.deploymentParameters = params; + await this.performAzureDeployment(3); + } + + protected async performAzureDeployment(retryCount = 0): Promise { + if (this.deploymentParameters.properties["mode"] === "Validation") { + return this.validateDeployment(); + } else { + console.log(tl.loc("StartingDeployment")); + return new Promise((resolve, reject) => { + this.taskParameters.deploymentName = this.taskParameters.deploymentName || utils.createDeploymentName(this.taskParameters); + console.log(tl.loc("LogDeploymentName", this.taskParameters.deploymentName)); + this.armClient.deployments.createOrUpdate(this.taskParameters.deploymentName, this.deploymentParameters, (error, result, request, response) => { + if (error) { + if(this.taskParameters.deploymentScope === "Resource Group" && error.code == "ResourceGroupNotFound" && retryCount > 0){ + return this.waitAndPerformAzureDeployment(retryCount); + } + utils.writeDeploymentErrors(this.taskParameters, error); + return reject(tl.loc("CreateTemplateDeploymentFailed")); + } + if (result && result["properties"] && result["properties"]["outputs"] && utils.isNonEmpty(this.taskParameters.deploymentOutputs)) { + tl.setVariable(this.taskParameters.deploymentOutputs, JSON.stringify(result["properties"]["outputs"])); + console.log(tl.loc("AddedOutputVariable", this.taskParameters.deploymentOutputs)); + } + + console.log(tl.loc("CreateTemplateDeploymentSucceeded")); + resolve(); + }); + }); + } + } + + protected validateDeployment(): Promise { + return new Promise((resolve, reject) => { + console.log(tl.loc("StartingValidation")); + this.deploymentParameters.properties["mode"] = "Incremental"; + this.taskParameters.deploymentName = this.taskParameters.deploymentName || utils.createDeploymentName(this.taskParameters); + console.log(tl.loc("LogDeploymentName", this.taskParameters.deploymentName)); + this.armClient.deployments.validate(this.taskParameters.deploymentName, this.deploymentParameters, (error, result, request, response) => { + if (error) { + return reject(tl.loc("CreateTemplateDeploymentValidationFailed", utils.getError(error))); + } + if (result.error) { + utils.writeDeploymentErrors(this.taskParameters, result.error); + return reject(tl.loc("CreateTemplateDeploymentFailed")); + } else { + console.log(tl.loc("ValidDeployment")); + resolve(); + } + }); + }); + } + + private async waitAndPerformAzureDeployment(retryCount): Promise { + await sleepFor(3); + return this.performAzureDeployment(retryCount - 1); + } +} \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/FileEncoding.ts b/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/FileEncoding.ts new file mode 100644 index 000000000000..dc2452386603 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/FileEncoding.ts @@ -0,0 +1,105 @@ +//File Encoding detected to be : utf-32be, which is not supported by Node.js +//'Unable to detect encoding of file ' + typeCode +//'File buffer is too short to detect encoding type' + +var fs = require('fs'); +import tl = require('azure-pipelines-task-lib'); + +export class FileEncoding { + public type: string; + public usesBOM: boolean; + constructor(type: string, usesBOM: boolean) { + this.type = type; + this.usesBOM = usesBOM; + } +} + +function detectFileEncodingWithBOM(buffer: Buffer): FileEncoding { + tl.debug('Detecting file encoding using BOM'); + var type: string; + if (buffer.slice(0, 3).equals(new Buffer([239, 187, 191]))) { + type = 'utf-8'; + } + else if (buffer.slice(0, 4).equals(new Buffer([255, 254, 0, 0]))) { + type = 'utf-32le'; + } + else if (buffer.slice(0, 2).equals(new Buffer([254, 255]))) { + type = 'utf-16be'; + } + else if (buffer.slice(0, 2).equals(new Buffer([255, 254]))) { + type = 'utf-16le'; + } + else if (buffer.slice(0, 4).equals(new Buffer([0, 0, 254, 255]))) { + type = 'utf-32be'; + } + else { + tl.debug('Unable to detect File encoding using BOM'); + return null; + } + return new FileEncoding(type, true); +} + +function detectFileEncodingWithoutBOM(buffer: Buffer): FileEncoding { + tl.debug('Detecting file encoding without BOM'); + + var typeCode = 0; + var type: string; + var codeForUtf8 = 0 + for (var index = 0; index < 4 && index < buffer.length; index++) { + typeCode = typeCode << 1; + typeCode = typeCode | (buffer[index] > 0 ? 1 : 0); + codeForUtf8 = codeForUtf8 << 1; + codeForUtf8++; + } + switch (typeCode) { + case 1: + type = 'utf-32be'; + break; + case 5: + type = 'utf-16be'; + break; + case 8: + type = 'utf-32le'; + break; + case 10: + type = 'utf-16le'; + break; + default: + if (codeForUtf8 == typeCode) { + type = 'utf-8'; + } + else { + return null; + } + } + return new FileEncoding(type, false); +} +export function detectFileEncoding(fileName: string, buffer: Buffer): FileEncoding { + var fileEncoding: FileEncoding = detectFileEncodingWithBOM(buffer); + if (fileEncoding == null) { + if (buffer.length < 4) { + tl.debug('Short file buffer error on file' + fileName + '. length: ' + buffer.length); + } + fileEncoding = detectFileEncodingWithoutBOM(buffer); + } + + if (fileEncoding == null) { + throw new Error(tl.loc("CouldNotDetectEncoding", fileName)); + } + console.log(tl.loc("DetectedFileEncoding", fileName, fileEncoding.type)); + return fileEncoding; +} + +export function readFileContentsAsText(fileName: string): string { + var buffer = fs.readFileSync(fileName); + var supportedFileEncodings = ["utf-8", "utf-16le"] + var fileEncoding = detectFileEncoding(fileName, buffer); + if (supportedFileEncodings.indexOf(fileEncoding.type) < 0) { + throw new Error(tl.loc('EncodingNotSupported', fileName, fileEncoding.type)); + } + var fileContents: string = buffer.toString(fileEncoding.type); + if (fileEncoding.usesBOM) { + fileContents = fileContents.slice(1); + } + return fileContents; +} \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/ParameterParser.ts b/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/ParameterParser.ts new file mode 100644 index 000000000000..c079284530f8 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/ParameterParser.ts @@ -0,0 +1,154 @@ +// This class manages the powershell parameters format + +export interface NameValuePair { + name: string; + value: string; +} + +export class PowerShellParameters { + + // Parses the string and retuens array of key-value pairs + public static parse(input: string, removeQuotes?: boolean, escapeCharacter?: string): NameValuePair[] { + if (!!escapeCharacter) { + this.escapeCharacter = escapeCharacter; + } + var result: NameValuePair[] = []; + var index = 0; + var obj: NameValuePair = { name: "", value: "" }; + + input = input.trim(); + + while (index < input.length) { + var literalData = this.findLiteral(input, index); + var nextIndex = literalData.currentPosition; + var hasSpecialCharacter = literalData.hasSpecialCharacter; + var literal = input.substr(index, nextIndex - index).trim(); + if (this.isName(literal, hasSpecialCharacter)) { + if (obj.name) { + result.push(obj); + obj = { name: "", value: "" }; + } + //substr from index 1 to remove '-' in the starting of literal + obj.name = literal.substr(1, literal.length); + } + else { + obj.value = literal; + result.push(obj); + obj = { name: "", value: "" }; + } + + index = nextIndex + 1; + } + + if (obj.name) { + result.push(obj); + } + if (!!removeQuotes) { + for (var name in result) { + result[name].value = result[name].value.replace(/^"(.*)"$/, '$1'); + } + } + + this.escapeCharacter = "`"; // Resetting escape character + return result; + } + + private static isName(literal: string, hasSpecialCharacter: boolean): boolean { + return literal[0] === '-' && !hasSpecialCharacter && isNaN(Number(literal)); + } + + private static findLiteral(input, currentPosition) { + var hasSpecialCharacter = false; + for (; currentPosition < input.length; currentPosition++) { + if (input[currentPosition] == " " || input[currentPosition] == "\t") { + for (; currentPosition < input.length; currentPosition++) { + if (input[currentPosition + 1] != " " && input[currentPosition + 1] != "\t") { + break; + } + } + + break; + } + else if (input[currentPosition] == "(") { + currentPosition = this.findClosingBracketIndex(input, currentPosition + 1, ")"); + hasSpecialCharacter = true; + } + else if (input[currentPosition] == "[") { + currentPosition = this.findClosingBracketIndex(input, currentPosition + 1, "]"); + hasSpecialCharacter = true; + } + else if (input[currentPosition] == "{") { + currentPosition = this.findClosingBracketIndex(input, currentPosition + 1, "}"); + hasSpecialCharacter = true; + } + else if (input[currentPosition] == "\"") { + //keep going till this one closes + currentPosition = this.findClosingQuoteIndex(input, currentPosition + 1, "\""); + hasSpecialCharacter = true; + } + else if (input[currentPosition] == "'") { + //keep going till this one closes + currentPosition = this.findClosingQuoteIndex(input, currentPosition + 1, "'"); + hasSpecialCharacter = true; + } + else if (input[currentPosition] == this.escapeCharacter) { + currentPosition++; + hasSpecialCharacter = true; + if (currentPosition >= input.length) { + break; + } + } + + } + return { currentPosition: currentPosition, hasSpecialCharacter: hasSpecialCharacter }; + } + + private static findClosingBracketIndex(input, currentPosition, closingBracket): number { + for (; currentPosition < input.length; currentPosition++) { + if (input[currentPosition] == closingBracket) { + break; + } + else if (input[currentPosition] == "(") { + currentPosition = this.findClosingBracketIndex(input, currentPosition + 1, ")"); + } + else if (input[currentPosition] == "[") { + currentPosition = this.findClosingBracketIndex(input, currentPosition + 1, "]"); + } + else if (input[currentPosition] == "{") { + currentPosition = this.findClosingBracketIndex(input, currentPosition + 1, "}"); + } + else if (input[currentPosition] == "\"") { + currentPosition = this.findClosingQuoteIndex(input, currentPosition + 1, "\""); + } + else if (input[currentPosition] == "'") { + currentPosition = this.findClosingQuoteIndex(input, currentPosition + 1, "'"); + } + else if (input[currentPosition] == this.escapeCharacter) { + currentPosition++; + if (currentPosition >= input.length) { + break; + } + } + } + + return currentPosition; + } + + private static findClosingQuoteIndex(input, currentPosition, closingQuote) { + for (; currentPosition < input.length; currentPosition++) { + if (input[currentPosition] == this.escapeCharacter) { + currentPosition++; + if (currentPosition >= input.length) { + break; + } + } + else if (input[currentPosition] == closingQuote) { + break; + } + } + + return currentPosition; + } + + private static escapeCharacter = "`"; +} diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/ResourceGroup.ts b/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/ResourceGroup.ts new file mode 100644 index 000000000000..a667abc13064 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/ResourceGroup.ts @@ -0,0 +1,67 @@ +import tl = require("azure-pipelines-task-lib/task"); + +import armDeployTaskParameters = require("../models/TaskParameters"); +import armResource = require("azure-arm-rest-v2/azure-arm-resource"); +import utils = require("./Utils"); +import { DeploymentScopeBase } from "./DeploymentScopeBase"; + +export class ResourceGroup extends DeploymentScopeBase { + + public resourceManagementClient: armResource.ResourceManagementClient; + + constructor(resourceManagementClient: armResource.ResourceManagementClient, taskParameters: armDeployTaskParameters.TaskParameters) { + super(resourceManagementClient, taskParameters); + this.resourceManagementClient = resourceManagementClient; + } + + public async deploy(): Promise { + await this.createResourceGroupIfRequired(); + await this.createTemplateDeployment(); + } + + public deleteResourceGroup(): Promise { + return new Promise((resolve, reject) => { + console.log(tl.loc("DeletingResourceGroup", this.taskParameters.resourceGroupName)); + this.resourceManagementClient.resourceGroup.deleteMethod((error, result, request, response) => { + if (error) { + return reject(tl.loc("CouldNotDeletedResourceGroup", this.taskParameters.resourceGroupName, utils.getError(error))); + } + console.log(tl.loc("DeletedResourceGroup", this.taskParameters.resourceGroupName)); + resolve(); + }); + }); + } + + private async createResourceGroupIfRequired() { + var exists = await this.checkResourceGroupExistence() + if (!exists) { + await this.createResourceGroup(); + } + } + + private checkResourceGroupExistence(): Promise { + console.log(tl.loc("CheckResourceGroupExistence", this.taskParameters.resourceGroupName)); + return new Promise((resolve, reject) => { + this.resourceManagementClient.resourceGroup.checkExistence((error, exists, request, response) => { + if (error) { + return reject(tl.loc("ResourceGroupStatusFetchFailed", utils.getError(error))); + } + console.log(tl.loc("ResourceGroupStatus", exists)); + resolve(exists); + }); + }); + } + + private createResourceGroup(): Promise { + return new Promise((resolve, reject) => { + console.log(tl.loc("CreatingNewRG", this.taskParameters.resourceGroupName)); + this.resourceManagementClient.resourceGroup.createOrUpdate({ "name": this.taskParameters.resourceGroupName, "location": this.taskParameters.location }, (error, result, request, response) => { + if (error) { + return reject(tl.loc("ResourceGroupCreationFailed", utils.getError(error))); + } + console.log(tl.loc("CreatedRG")); + resolve(); + }); + }); + } +} \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/Utils.ts b/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/Utils.ts new file mode 100644 index 000000000000..ec2b1e18c97e --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/operations/Utils.ts @@ -0,0 +1,408 @@ +import util = require("util"); +import path = require("path"); +import tl = require("azure-pipelines-task-lib/task"); +import fs = require("fs"); + +import armDeployTaskParameters = require("../models/TaskParameters"); +import { PowerShellParameters, NameValuePair } from "./ParameterParser"; +import fileEncoding = require('./FileEncoding'); +import { TemplateObject, ParameterValue } from "../models/Types"; +import httpInterfaces = require("typed-rest-client/Interfaces"); +import { DeploymentParameters } from "./DeploymentParameters"; + +var hm = require("typed-rest-client/HttpClient"); +var uuid = require("uuid"); + +let proxyUrl: string = tl.getVariable("agent.proxyurl"); +var requestOptions: httpInterfaces.IRequestOptions = proxyUrl ? { + proxy: { + proxyUrl: proxyUrl, + proxyUsername: tl.getVariable("agent.proxyusername"), + proxyPassword: tl.getVariable("agent.proxypassword"), + proxyBypassHosts: tl.getVariable("agent.proxybypasslist") ? JSON.parse(tl.getVariable("agent.proxybypasslist")) : null + } +} : {}; + +let ignoreSslErrors: string = tl.getVariable("VSTS_ARM_REST_IGNORE_SSL_ERRORS"); +requestOptions.ignoreSslError = ignoreSslErrors && ignoreSslErrors.toLowerCase() == "true"; + +let httpClient = new hm.HttpClient(tl.getVariable("AZURE_HTTP_USER_AGENT"), null, requestOptions); + +function formatNumber(num: number): string { + return ("0" + num).slice(-2); +} + +class Utils { + public static isNonEmpty(str: string): boolean { + return (!!str && !!str.trim()); + } + + public static getError(error: any): string { + if (error && error.message) { + return JSON.stringify(error.message); + } + + if (typeof error === "string") { + return error; + } + + return JSON.stringify(error); + } + + public static buildErrorString(errors: string[]): string { + let index: number = 1; + return errors.map(error => !!error ? util.format("%s. %s \n", index++, error) : "").join(""); + } + + public static stripJsonComments(content) { + if (!content || (content.indexOf("//") < 0 && content.indexOf("/*") < 0)) { + return content; + } + + var currentChar; + var nextChar; + var insideQuotes = false; + var contentWithoutComments = ''; + var insideComment = 0; + var singlelineComment = 1; + var multilineComment = 2; + + for (var i = 0; i < content.length; i++) { + currentChar = content[i]; + nextChar = i + 1 < content.length ? content[i + 1] : ""; + + if (insideComment) { + var update = false; + if (insideComment == singlelineComment && (currentChar + nextChar === '\r\n' || currentChar === '\n')) { + i--; + insideComment = 0; + continue; + } + + if (insideComment == multilineComment && currentChar + nextChar === '*/') { + i++; + insideComment = 0; + continue; + } + + } else { + if (insideQuotes && currentChar == "\\") { + contentWithoutComments += currentChar + nextChar; + i++; // Skipping checks for next char if escaped + continue; + } + else { + if (currentChar == '"') { + insideQuotes = !insideQuotes; + } + + if (!insideQuotes) { + if (currentChar + nextChar === '//') { + insideComment = singlelineComment; + i++; + } + + if (currentChar + nextChar === '/*') { + insideComment = multilineComment; + i++; + } + } + } + } + + if (!insideComment) { + contentWithoutComments += content[i]; + } + } + + return contentWithoutComments; + } + + public static writeDeploymentErrors(taskParameters: armDeployTaskParameters.TaskParameters, error): void { + console.log(tl.loc("ErrorsInYourDeployment", error.code)); + if (error.message) { + tl.error(error.message); + if (error.details) { + tl.error(tl.loc("Details")); + + + for (var i = 0; i < error.details.length; i++) { + var errorMessage = null; + let policyLink = null; + + if (error.details[i].code === "RequestDisallowedByPolicy") { + policyLink = this.getPolicyHelpLink(taskParameters, error.details[i]); + errorMessage = this.getPolicyErrorMessage(error.details[i]); + } else { + errorMessage = util.format("%s: %s", error.details[i].code, error.details[i].message); + if(error.details[i].details) { + if(typeof error.details[i].details == 'object') { + errorMessage += " " + JSON.stringify(error.details[i].details); + } else { + errorMessage += " " + String(error.details[i].details); + } + } + } + + tl.error(errorMessage); + if (policyLink) { + tl.error(util.format("[%s](%s)", tl.loc("MoreInformationOnAzurePortal"), policyLink)); + } + } + + + } + } else { + tl.error(error); + } + } + + public static async getDeploymentObjectForPublicURL(taskParameters: armDeployTaskParameters.TaskParameters): Promise { + var properties = {}; + properties["templateLink"] = { + uri: taskParameters.csmFileLink + }; + var parameters: Map = {} as Map; + var deploymentParameters = new DeploymentParameters(properties); + + if (this.isNonEmpty(taskParameters.csmParametersFileLink)) { + if (this.isNonEmpty(taskParameters.overrideParameters)) { + var contents = await this.downloadFile(taskParameters.csmParametersFileLink); + parameters = JSON.parse(this.stripJsonComments(contents)).parameters; + } + else { + deploymentParameters.properties["parametersLink"] = { + uri: taskParameters.csmParametersFileLink + }; + } + } + + if (this.isNonEmpty(taskParameters.overrideParameters)) { + tl.debug("Downloading CSM Template File.. " + taskParameters.csmFileLink); + var templateFile = await this.downloadFile(taskParameters.csmFileLink); + var template; + try { + var template = JSON.parse(this.stripJsonComments(templateFile)); + tl.debug("Loaded CSM File"); + } + catch (error) { + throw new Error(tl.loc("TemplateParsingFailed", this.getError(error.message))); + } + parameters = this.updateOverrideParameters(taskParameters, template, parameters); + parameters = this.sanitizeParameters(parameters); + deploymentParameters.properties["parameters"] = parameters; + } + + deploymentParameters.updateCommonProperties(taskParameters.deploymentMode); + return deploymentParameters; + } + + public static createDeploymentName(taskParameters: armDeployTaskParameters.TaskParameters): string { + var name: string; + if (taskParameters.templateLocation == "Linked artifact") { + name = tl.findMatch(tl.getVariable("System.DefaultWorkingDirectory"), taskParameters.csmFile)[0]; + } else { + name = taskParameters.csmFileLink; + } + name = path.basename(name).split(".")[0].replace(" ", ""); + name = name.substr(0, 40); + var timestamp = new Date(Date.now()); + var uniqueId = uuid().substr(0, 4); + var suffix = util.format("%s%s%s-%s%s%s-%s", timestamp.getFullYear(), + formatNumber(timestamp.getMonth() + 1), + formatNumber(timestamp.getDate()), + formatNumber(timestamp.getHours()), + formatNumber(timestamp.getMinutes()), + formatNumber(timestamp.getSeconds()), + uniqueId); + var deploymentName = util.format("%s-%s", name, suffix); + if (deploymentName.match(/^[-\w\._\(\)]+$/) === null) { + deploymentName = util.format("deployment-%s", suffix); + } + return deploymentName; + } + + public static getDeploymentDataForLinkedArtifact(taskParameters: armDeployTaskParameters.TaskParameters): DeploymentParameters { + var template: TemplateObject; + var fileMatches = tl.findMatch(tl.getVariable("System.DefaultWorkingDirectory"), taskParameters.csmFile); + if (fileMatches.length > 1) { + throw new Error(tl.loc("TemplateFilePatternMatchingMoreThanOneFile", fileMatches)); + } + if (fileMatches.length < 1) { + throw new Error(tl.loc("TemplateFilePatternMatchingNoFile")); + } + var csmFilePath = fileMatches[0]; + if (!fs.lstatSync(csmFilePath).isDirectory()) { + tl.debug("Loading CSM Template File.. " + csmFilePath); + try { + template = JSON.parse(this.stripJsonComments(fileEncoding.readFileContentsAsText(csmFilePath))); + } + catch (error) { + throw new Error(tl.loc("TemplateParsingFailed", csmFilePath, this.getError(error.message))); + } + tl.debug("Loaded CSM File"); + } else { + throw new Error(tl.loc("CsmFilePatternMatchesADirectoryInsteadOfAFile", csmFilePath)); + } + + var parameters: Map = {} as Map; + if (this.isNonEmpty(taskParameters.csmParametersFile)) { + var fileMatches = tl.findMatch(tl.getVariable("System.DefaultWorkingDirectory"), taskParameters.csmParametersFile); + if (fileMatches.length > 1) { + throw new Error(tl.loc("TemplateParameterFilePatternMatchingMoreThanOneFile", fileMatches)); + } + if (fileMatches.length < 1) { + throw new Error(tl.loc("TemplateParameterFilePatternMatchingNoFile")); + } + var csmParametersFilePath = fileMatches[0]; + if (!fs.lstatSync(csmParametersFilePath).isDirectory()) { + tl.debug("Loading Parameters File.. " + csmParametersFilePath); + try { + var parameterFile = JSON.parse(this.stripJsonComments(fileEncoding.readFileContentsAsText(csmParametersFilePath))); + tl.debug("Loaded Parameters File"); + parameters = parameterFile["parameters"] as Map; + } catch (error) { + throw new Error(tl.loc("ParametersFileParsingFailed", csmParametersFilePath, this.getError(error.message))); + } + } else { + if (tl.filePathSupplied("csmParametersFile")) { + throw new Error(tl.loc("ParametersPatternMatchesADirectoryInsteadOfAFile", csmParametersFilePath)); + } + } + } + + if (this.isNonEmpty(taskParameters.overrideParameters)) { + parameters = this.updateOverrideParameters(taskParameters, template, parameters); + } + + parameters = this.sanitizeParameters(parameters); + + var deploymentParameters = new DeploymentParameters({ + template: template, + parameters: parameters + }); + deploymentParameters.updateCommonProperties(taskParameters.deploymentMode); + return deploymentParameters; + } + + private static getPolicyHelpLink(taskParameters: armDeployTaskParameters.TaskParameters, errorDetail) { + var additionalInfo = errorDetail.additionalInfo; + if (!!additionalInfo) { + for (var i = 0; i < additionalInfo.length; i++) { + if (!!additionalInfo[i].info && !!additionalInfo[i].info.policyAssignmentId) { + let portalUrl = taskParameters.endpointPortalUrl ? taskParameters.endpointPortalUrl : "https://portal.azure.com"; + return portalUrl + "#blade/Microsoft_Azure_Policy/EditAssignmentBlade/id/" + encodeURIComponent(additionalInfo[i].info.policyAssignmentId); + } + } + } + + return null; + } + + private static getPolicyErrorMessage(errorDetail): string { + var errorMessage = errorDetail.message; + + if (!!errorMessage) { + errorMessage = errorMessage.split(".")[0] + "."; + } + + var additionalInfo = errorDetail.additionalInfo; + if (!!additionalInfo) { + for (var i = 0; i < additionalInfo.length; i++) { + if (!!additionalInfo[i].info) { + errorMessage = util.format("%s %s %s, %s %s, %s %s.", errorMessage, tl.loc("ErrorType"), additionalInfo[i].type, tl.loc("PolicyDefinitionName"), additionalInfo[i].info.policyDefinitionDisplayName, tl.loc("PolicyAssignmentName"), additionalInfo[i].info.policyAssignmentName); + } + } + } + + return errorMessage; + } + + private static castToType(value: string, type: string): any { + switch (type.toLowerCase()) { + case "int": + case "object": + case "secureobject": + case "array": + case "bool": + return JSON.parse(value); + case "string": + case "securestring": + return JSON.parse(`"` + value + `"`); // Adding trailing quotes for JSON parser to detect string + default: + // Sending as string + break; + } + return value; + } + + private static updateOverrideParameters(taskParameters: armDeployTaskParameters.TaskParameters, template: TemplateObject, parameters: Map): Map { + tl.debug("Overriding Parameters.."); + + var overrideParameters: NameValuePair[] = PowerShellParameters.parse(taskParameters.overrideParameters, true, "\\"); + for (var overrideParameter of overrideParameters) { + tl.debug("Overriding key: " + overrideParameter.name); + if (taskParameters.addSpnToEnvironment) { + if (overrideParameter.value === "$servicePrincipalId") { + overrideParameter.value = tl.getEndpointAuthorizationParameter(taskParameters.connectedService, 'serviceprincipalid', true); + } + if (overrideParameter.value === "$servicePrincipalKey") { + overrideParameter.value = tl.getEndpointAuthorizationParameter(taskParameters.connectedService, 'serviceprincipalkey', false); + } + } + + try { + overrideParameter.value = this.castToType(overrideParameter.value, template.parameters[overrideParameter.name].type); + } catch (error) { + console.log(tl.loc("ErrorWhileParsingParameter", overrideParameter.name, error.toString())); + } + parameters[overrideParameter.name] = { + value: overrideParameter.value + } as ParameterValue; + } + return parameters; + } + + private static downloadFile(url): Promise { + return new Promise((resolve, reject) => { + httpClient.get(url, {}).then(async (response) => { + if (response.message.statusCode == 200) { + let contents: string = ""; + try { + contents = await response.readBody(); + contents = contents.replace(/^\uFEFF/, ''); // Remove UTF-8 BOM if present. + } catch (error) { + reject(tl.loc("UnableToReadResponseBody", error)); + } + resolve(contents); + } else { + var errorMessage = response.message.statusCode.toString() + ": " + response.message.statusMessage; + return reject(tl.loc("FileFetchFailed", url, errorMessage)); + } + }, (error) => { + return reject(tl.loc("FileFetchFailed", url, error)); + }); + }); + } + + private static sanitizeParameters(parameters: Map): Map { + var result: Map = {} as Map; + for (var key in parameters) { + if (!!parameters[key]) { + if (parameters[key].hasOwnProperty("value")) { + result[key] = { + value: parameters[key].value + } as ParameterValue; + } else if (parameters[key].hasOwnProperty("reference")) { + result[key] = { + reference: parameters[key].reference + } as ParameterValue; + } + } + } + + return result; + } +} + +export = Utils; \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/package-lock.json b/Tasks/AzureResourceManagerTemplateDeploymentV3/package-lock.json new file mode 100644 index 000000000000..b7c278a62110 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/package-lock.json @@ -0,0 +1,216 @@ +{ + "name": "AzureResourceManagerTemplateDeployment", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@types/mocha": { + "version": "2.2.48", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.48.tgz", + "integrity": "sha512-nlK/iyETgafGli8Zh9zJVCTicvU3iajSkRwOh3Hhiva598CMqNJ4NcVCGMTGKpGpTYj/9R8RLzS9NAykSSCqGw==" + }, + "@types/node": { + "version": "6.0.68", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.68.tgz", + "integrity": "sha1-DEO2uLlEX+uGoPvTRX4/S8WR5m0=" + }, + "@types/q": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.0.7.tgz", + "integrity": "sha512-0WS7XU7sXzQ7J1nbnMKKYdjrrFoO3YtZYgUzeV8JFXffPnHfvSJQleR70I8BOAsOm14i4dyaAZ3YzqIl1YhkXQ==" + }, + "azure-arm-rest-v2": { + "version": "file:../../_build/Tasks/Common/azure-arm-rest-v2-2.0.0.tgz", + "requires": { + "@types/mocha": "2.2.48", + "@types/node": "6.0.68", + "@types/q": "1.0.7", + "azure-pipelines-task-lib": "2.8.0", + "jsonwebtoken": "7.3.0", + "q": "1.4.1", + "typed-rest-client": "0.12.0" + } + }, + "azure-pipelines-task-lib": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.8.0.tgz", + "integrity": "sha512-PR8oap9z2j+o455W3PwAfB4SX1p4GdJc9OHQaQV0V+iQS1IBY6dVgcNSQMkHAXb0V1bbuLOFBLanXPe5eSgGTQ==", + "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-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + }, + "isemail": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", + "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo=" + }, + "joi": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", + "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=", + "requires": { + "hoek": "2.x.x", + "isemail": "1.x.x", + "moment": "2.x.x", + "topo": "1.x.x" + } + }, + "jsonwebtoken": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.3.0.tgz", + "integrity": "sha1-hRGNanDj/M3xQ4n056HD+cip+7o=", + "requires": { + "joi": "^6.10.1", + "jws": "^3.1.4", + "lodash.once": "^4.0.0", + "ms": "^0.7.1", + "xtend": "^4.0.1" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "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=" + }, + "moment": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.21.0.tgz", + "integrity": "sha512-TCZ36BjURTeFTM/CwRcViQlfkMvL1/vFISuNLO5GkcVm1+QHfbSiNqZuWeMFjj1/3+uAjXswgRk30j1kkLYJBQ==" + }, + "ms": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz", + "integrity": "sha1-cIFVpeROM/X9D8U+gdDUCpG+H/8=" + }, + "q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=" + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "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=" + }, + "topo": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz", + "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=", + "requires": { + "hoek": "2.x.x" + } + }, + "tunnel": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.4.tgz", + "integrity": "sha1-LTeFoVjBdMmhbcLARuxfxfF0IhM=" + }, + "typed-rest-client": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-0.12.0.tgz", + "integrity": "sha1-Y3b1Un9CfaEh3K/f1+QeEyHgcgw=", + "requires": { + "tunnel": "0.0.4", + "underscore": "1.8.3" + } + }, + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + } + } +} \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/package.json b/Tasks/AzureResourceManagerTemplateDeploymentV3/package.json new file mode 100644 index 000000000000..2c9feca0cdc7 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/package.json @@ -0,0 +1,10 @@ +{ + "name": "AzureResourceManagerTemplateDeployment", + "main": "main.js", + "dependencies": { + "azure-arm-rest-v2": "file:../../_build/Tasks/Common/azure-arm-rest-v2-2.0.0.tgz", + "azure-pipelines-task-lib": "2.8.0", + "moment": "2.21.0", + "typed-rest-client": "0.12.0" + } +} diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/task.json b/Tasks/AzureResourceManagerTemplateDeploymentV3/task.json new file mode 100644 index 000000000000..f65702d96cd3 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/task.json @@ -0,0 +1,299 @@ +{ + "id": "94A74903-F93F-4075-884F-DC11F34058B4", + "name": "AzureResourceManagerTemplateDeployment", + "friendlyName": "ARM template deployment", + "description": "Deploy an Azure Resource Manager (ARM) template to all the deployment scopes", + "helpUrl": "https://docs.microsoft.com/azure/devops/pipelines/tasks/deploy/azure-resource-group-deployment", + "helpMarkDown": "[Learn more about this task](https://aka.ms/armtaskreadme)", + "category": "Deploy", + "releaseNotes": "- Added support for deployment at all the deployment scopes.\n- Removed all the VM related actions.", + "visibility": [ + "Build", + "Release" + ], + "author": "Microsoft Corporation", + "version": { + "Major": 3, + "Minor": 0, + "Patch": 0 + }, + "preview": "true", + "demands": [], + "minimumAgentVersion": "2.119.1", + "groups": [ + { + "name": "AzureDetails", + "displayName": "Azure Details", + "isExpanded": true + }, + { + "name": "Template", + "displayName": "Template", + "isExpanded": true, + "visibleRule": "action = Create Or Update Resource Group || deploymentScope != Resource Group" + }, + { + "name": "Advanced", + "displayName": "Advanced", + "isExpanded": true, + "visibleRule": "action = Create Or Update Resource Group || deploymentScope != Resource Group" + } + ], + "inputs": [ + { + "name": "deploymentScope", + "type": "pickList", + "label": "Deployment scope", + "defaultValue": "Resource Group", + "required": "true", + "groupName": "AzureDetails", + "helpMarkDown": "Deployment scope of the deployment. To know more abour deployment scopes, refer this [link](https://docs.microsoft.com/bs-latn-ba/Azure/azure-resource-manager/resource-group-template-deploy-rest#deployment-scope)", + "options": { + "Management Group": "Management Group", + "Subscription" : "Subscription", + "Resource Group" : "Resource Group" + } + }, + { + "name": "ConnectedServiceName", + "type": "connectedService:AzureRM", + "label": "Azure Resource Manager connection", + "defaultValue": "", + "required": true, + "groupName": "AzureDetails", + "helpMarkDown": "Select the Azure Resource Manager service connection having access to the selected deployment scope.", + "properties": { + "EndpointFilterRule": "ScopeLevel != AzureMLWorkspace" + } + }, + { + "name": "subscriptionName", + "type": "pickList", + "label": "Subscription", + "required": true, + "groupName": "AzureDetails", + "helpMarkDown": "Select the Azure subscription", + "visibleRule": "deploymentScope != Management Group" + }, + { + "name": "action", + "type": "pickList", + "label": "Action", + "defaultValue": "Create Or Update Resource Group", + "required": true, + "groupName": "AzureDetails", + "helpMarkDown": "Action to be performed on the Azure resources or resource group.", + "options": { + "Create Or Update Resource Group": "Create or update resource group", + "DeleteRG": "Delete resource group" + }, + "visibleRule": "deploymentScope = Resource Group" + }, + { + "name": "resourceGroupName", + "type": "pickList", + "label": "Resource group", + "required": true, + "groupName": "AzureDetails", + "helpMarkDown": "Provide the name of a resource group.", + "properties": { + "EditableOptions": "True" + }, + "visibleRule": "deploymentScope = Resource Group" + }, + { + "name": "location", + "type": "pickList", + "label": "Location", + "required": true, + "helpMarkDown": "For Resource Group deployment scope: Location for deploying the resource group. If the resource group already exists in the subscription, then this value will be ignored.\n For other deployment scope: Location to store deployment metadata.", + "groupName": "AzureDetails", + "properties": { + "EditableOptions": "True" + }, + "visibleRule": "action = Create Or Update Resource Group || deploymentScope != Resource Group" + }, + { + "name": "templateLocation", + "type": "pickList", + "label": "Template location", + "required": true, + "defaultValue": "Linked artifact", + "groupName": "Template", + "options": { + "Linked artifact": "Linked artifact", + "URL of the file": "URL of the file" + } + }, + { + "name": "csmFileLink", + "type": "string", + "label": "Template link", + "defaultValue": "", + "required": true, + "groupName": "Template", + "helpMarkDown": "Specify the URL of the template file. Example: [https://raw.githubusercontent.com/Azure/...](https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/101-vm-simple-windows/azuredeploy.json) \n\nTo deploy a template stored in a private storage account, retrieve and include the shared access signature (SAS) token in the URL of the template. Example: `/template.json?` To upload a template file (or a linked template) to a storage account and generate a SAS token, you could use [Azure file copy](https://aka.ms/azurefilecopyreadme) task or follow the steps using [PowerShell](https://go.microsoft.com/fwlink/?linkid=838080) or [Azure CLI](https://go.microsoft.com/fwlink/?linkid=836911).\n\nTo view the template parameters in a grid, click on “…” next to Override template parameters text box. This feature requires that CORS rules are enabled at the source. If templates are in Azure storage blob, refer to [this](https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Cross-Origin-Resource-Sharing--CORS--Support-for-the-Azure-Storage-Services?redirectedfrom=MSDN#understanding-cors-requests) to enable CORS.", + "visibleRule": "templateLocation = URL of the file" + }, + { + "name": "csmParametersFileLink", + "type": "string", + "label": "Template parameters link", + "defaultValue": "", + "required": false, + "groupName": "Template", + "helpMarkDown": "Specify the URL of the parameters file. Example: [https://raw.githubusercontent.com/Azure/...](https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/101-vm-simple-windows/azuredeploy.parameters.json) \n\nTo use a file stored in a private storage account, retrieve and include the shared access signature (SAS) token in the URL of the template. Example: `/template.json?` To upload a parameters file to a storage account and generate a SAS token, you could use [Azure file copy](https://aka.ms/azurefilecopyreadme) task or follow the steps using [PowerShell](https://go.microsoft.com/fwlink/?linkid=838080) or [Azure CLI](https://go.microsoft.com/fwlink/?linkid=836911). \n\nTo view the template parameters in a grid, click on “…” next to Override template parameters text box. This feature requires that CORS rules are enabled at the source. If templates are in Azure storage blob, refer to [this](https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Cross-Origin-Resource-Sharing--CORS--Support-for-the-Azure-Storage-Services?redirectedfrom=MSDN#understanding-cors-requests) to enable CORS.", + "visibleRule": " templateLocation = URL of the file" + }, + { + "name": "csmFile", + "type": "filePath", + "label": "Template", + "defaultValue": "", + "required": true, + "groupName": "Template", + "visibleRule": " templateLocation = Linked artifact", + "helpMarkDown": "Specify the path or a pattern pointing to the Azure Resource Manager template. For more information about the templates see https://aka.ms/azuretemplates. To get started immediately use template https://aka.ms/sampletemplate." + }, + { + "name": "csmParametersFile", + "type": "filePath", + "label": "Template parameters", + "defaultValue": "", + "required": false, + "groupName": "Template", + "helpMarkDown": "Specify the path or a pattern pointing for the parameters file for the Azure Resource Manager template.", + "visibleRule": " templateLocation = Linked artifact" + }, + { + "name": "overrideParameters", + "type": "multiLine", + "label": "Override template parameters", + "defaultValue": "", + "required": false, + "groupName": "Template", + "helpMarkDown": "To view the template parameters in a grid, click on “…” next to Override Parameters textbox. This feature requires that CORS rules are enabled at the source. If templates are in Azure storage blob, refer to [this](https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Cross-Origin-Resource-Sharing--CORS--Support-for-the-Azure-Storage-Services?redirectedfrom=MSDN#understanding-cors-requests) to enable CORS. Or type the template parameters to override in the textbox. Example,
–storageName fabrikam –adminUsername $(vmusername) -adminPassword $(password) –azureKeyVaultName $(fabrikamFibre).
If the parameter value you're using has multiple words, enclose them in quotes, even if you're passing them using variables. For example, -name \"parameter value\" -name2 \"$(var)\"
To override object type parameters use stringified JSON objects. For example, -options [\"option1\"] -map {\"key1\": \"value1\" }. ", + "properties": { + "editorExtension": "ms.vss-services-azure.azurerg-parameters-grid" + } + }, + { + "name": "deploymentMode", + "type": "pickList", + "label": "Deployment mode", + "defaultValue": "Incremental", + "required": true, + "groupName": "Template", + "helpMarkDown": "Refer to [this](https://docs.microsoft.com/en-us/azure/azure-resource-manager/deployment-modes) for more details. \n\n Incremental mode handles deployments as incremental updates to the resource group. It leaves unchanged resources that exist in the resource group but are not specified in the template. \n\n Complete mode deletes resources that are not in your template. Complete mode takes relatively more time than incremental mode. If the task times out, consider increasing the timeout, or changing the mode to 'Incremental'. \n [Warning] This action will delete all the existing resources in the resource group that are not specified in the template. \n\n Validate mode enables you to find problems with the template before creating actual resources. \n\n By default, Incremental mode is used. \n\n 'Complete' mode is supported for 'Resource Group' Deployment scope only.", + "options": { + "Incremental": "Incremental", + "Complete": "Complete", + "Validation": "Validation only" + } + }, + { + "name": "deploymentName", + "type": "string", + "label": "Deployment name", + "defaultValue": "", + "required": false, + "groupName": "Advanced", + "helpMarkDown": "Specifies the name of the resource group deployment to create." + }, + { + "name": "deploymentOutputs", + "type": "string", + "label": "Deployment outputs", + "required": false, + "defaultValue": "", + "groupName": "Advanced", + "helpMarkDown": "Provide a name for the variable for the output variable which will contain the outputs section of the current deployment object in string format. You can use the “ConvertFrom-Json” PowerShell cmdlet to parse the JSON object and access the individual output values. For more details refer to [this](https://github.com/microsoft/azure-pipelines-tasks/tree/master/Tasks/AzureResourceManagerTemplateDeploymentV3#deployment-outputs)" + }, + { + "name": "addSpnToEnvironment", + "type": "boolean", + "label": "Access service principal details in override parameters", + "defaultValue": "false", + "required": false, + "helpMarkDown": "Adds service principal id and key of the Azure endpoint you chose to the script's execution environment. You can use these variables: `$servicePrincipalId` and `$servicePrincipalKey` in your override parameters like `-key $servicePrincipalKey`", + "groupName": "Advanced" + } + ], + "dataSourceBindings": [ + { + "target": "subscriptionName", + "endpointId": "$(ConnectedServiceName)", + "dataSourceName": "AzureSubscriptions", + "resultTemplate": "{ \"Value\" : \"{{{subscriptionId}}}\", \"DisplayValue\" : \"{{{displayName}}} ({{{subscriptionId}}})\" }" + }, + { + "target": "resourceGroupName", + "endpointId": "$(ConnectedServiceName)", + "dataSourceName": "AzureResourceGroupsByExplicitSubscription", + "parameters": { + "subscriptionId": "$(subscriptionName)" + } + }, + { + "target": "location", + "endpointId": "$(ConnectedServiceName)", + "dataSourceName": "AzureLocationsByDeploymentScope", + "parameters": { + "subscriptionId": "$(subscriptionName)", + "deploymentScope": "$(deploymentScope)" + } + } + ], + "instanceNameFormat": "ARM Template deployment: $(deploymentScope) scope", + "execution": { + "Node": { + "target": "main.js" + } + }, + "messages": { + "CheckResourceGroupExistence": "Checking if the following resource group exists: %s.", + "ResourceGroupStatusFetchFailed": "Failed to check the resource group status. Error: %s.", + "ResourceGroupStatus": "Resource group exists: %s.", + "ResourceGroupCreationFailed": "Failed to create the resource group. Error: %s", + "CreatingNewRG": "Creating resource Group: %s", + "CreatedRG": "Resource Group created successfully.", + "CreatingTemplateDeployment": "Creating deployment parameters.", + "TemplateParsingFailed": "Ensure the Template file ( '%s' ) is valid. Task failed while parsing with following error: %s", + "FileFetchFailed": "Failed to download the file. URL: '%s'. Error: %s", + "ParametersFileParsingFailed": "Ensure the Parameters file ( '%s' ) is valid. Task failed while parsing with following error: %s", + "StartingDeployment": "Starting Deployment.", + "CreateTemplateDeploymentSucceeded": "Successfully deployed the template.", + "CreateTemplateDeploymentFailed": "Task failed while creating or updating the template deployment.", + "ErrorsInYourDeployment": "There were errors in your deployment. Error code: %s.", + "Details": "Details:", + "ErrorType": "Error Type:", + "PolicyDefinitionName": "Policy Definition Name :", + "PolicyAssignmentName": "Policy Assignment Name :", + "StartingValidation": "Starting template validation.", + "ValidDeployment": "Template deployment validation was completed successfully.", + "CreateTemplateDeploymentValidationFailed": "Template validation failed. Error: %s.", + "DeletingResourceGroup": "Deleting resource group: %s", + "CouldNotDeletedResourceGroup": "Could not delete resource group: '%s'. Operation failed with error: %s", + "DeletedResourceGroup": "Deleted resource group: %s", + "InvalidAction": "This action is not defined. Check with the task author.", + "ARGD_ConstructorFailed": "Task failed while initializing. Error: %s", + "InvalidTemplateLocation": "The template location supplied is invalid. Task only supports 'Linked artifact' or 'URL of the file'", + "EncodingNotSupported": "Encoding of the file '%s' is '%s' which is not supported. Supported file encodings are ['utf-8', 'utf-16le']", + "CouldNotDetectEncoding": "Could not detect encoding of file '%s'", + "DetectedFileEncoding": "The detected encoding for file '%s' is '%s'", + "ErrorWhileParsingParameter": "There was an error while overriding '%s' parameter because of '%s', make sure it follows JavaScript Object Notation (JSON)", + "TemplateFilePatternMatchingMoreThanOneFile": "Found multiple files matching template file pattern: %s", + "TemplateParameterFilePatternMatchingMoreThanOneFile": "Found multiple files matching template parameters file pattern: %s", + "TemplateFilePatternMatchingNoFile": "Could not find any file matching the template file pattern", + "TemplateParameterFilePatternMatchingNoFile": "Could not find any file matching the template file pattern", + "ParametersPatternMatchesADirectoryInsteadOfAFile": "Parameters file pattern matches a directory instead of a file.", + "CsmFilePatternMatchesADirectoryInsteadOfAFile": "Template file pattern matches a directory instead of a file: %s", + "AddedOutputVariable": "Updated output variable '%s', which contains the outputs section of the current deployment object in string format.", + "UnableToReadResponseBody": "Unable to read response body. Error: %s", + "MoreInformationOnAzurePortal": "More information on Azure Portal", + "LogDeploymentName": "Deployment name is %s", + "ResourceGroupNameNotProvided": "Resource Group name should be provided", + "LocationNotProvided": "Location is required for deployment", + "ARMServiceConnectionScope": "ARM Service Conection deployment scope - %s" + } +} diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/task.loc.json b/Tasks/AzureResourceManagerTemplateDeploymentV3/task.loc.json new file mode 100644 index 000000000000..393fe8fa3cee --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/task.loc.json @@ -0,0 +1,299 @@ +{ + "id": "94A74903-F93F-4075-884F-DC11F34058B4", + "name": "AzureResourceManagerTemplateDeployment", + "friendlyName": "ms-resource:loc.friendlyName", + "description": "ms-resource:loc.description", + "helpUrl": "https://docs.microsoft.com/azure/devops/pipelines/tasks/deploy/azure-resource-group-deployment", + "helpMarkDown": "ms-resource:loc.helpMarkDown", + "category": "Deploy", + "releaseNotes": "ms-resource:loc.releaseNotes", + "visibility": [ + "Build", + "Release" + ], + "author": "Microsoft Corporation", + "version": { + "Major": 3, + "Minor": 0, + "Patch": 0 + }, + "preview": "true", + "demands": [], + "minimumAgentVersion": "2.119.1", + "groups": [ + { + "name": "AzureDetails", + "displayName": "ms-resource:loc.group.displayName.AzureDetails", + "isExpanded": true + }, + { + "name": "Template", + "displayName": "ms-resource:loc.group.displayName.Template", + "isExpanded": true, + "visibleRule": "action = Create Or Update Resource Group || deploymentScope != Resource Group" + }, + { + "name": "Advanced", + "displayName": "ms-resource:loc.group.displayName.Advanced", + "isExpanded": true, + "visibleRule": "action = Create Or Update Resource Group || deploymentScope != Resource Group" + } + ], + "inputs": [ + { + "name": "deploymentScope", + "type": "pickList", + "label": "ms-resource:loc.input.label.deploymentScope", + "defaultValue": "Resource Group", + "required": "true", + "groupName": "AzureDetails", + "helpMarkDown": "ms-resource:loc.input.help.deploymentScope", + "options": { + "Management Group": "Management Group", + "Subscription": "Subscription", + "Resource Group": "Resource Group" + } + }, + { + "name": "ConnectedServiceName", + "type": "connectedService:AzureRM", + "label": "ms-resource:loc.input.label.ConnectedServiceName", + "defaultValue": "", + "required": true, + "groupName": "AzureDetails", + "helpMarkDown": "ms-resource:loc.input.help.ConnectedServiceName", + "properties": { + "EndpointFilterRule": "ScopeLevel != AzureMLWorkspace" + } + }, + { + "name": "subscriptionName", + "type": "pickList", + "label": "ms-resource:loc.input.label.subscriptionName", + "required": true, + "groupName": "AzureDetails", + "helpMarkDown": "ms-resource:loc.input.help.subscriptionName", + "visibleRule": "deploymentScope != Management Group" + }, + { + "name": "action", + "type": "pickList", + "label": "ms-resource:loc.input.label.action", + "defaultValue": "Create Or Update Resource Group", + "required": true, + "groupName": "AzureDetails", + "helpMarkDown": "ms-resource:loc.input.help.action", + "options": { + "Create Or Update Resource Group": "Create or update resource group", + "DeleteRG": "Delete resource group" + }, + "visibleRule": "deploymentScope = Resource Group" + }, + { + "name": "resourceGroupName", + "type": "pickList", + "label": "ms-resource:loc.input.label.resourceGroupName", + "required": true, + "groupName": "AzureDetails", + "helpMarkDown": "ms-resource:loc.input.help.resourceGroupName", + "properties": { + "EditableOptions": "True" + }, + "visibleRule": "deploymentScope = Resource Group" + }, + { + "name": "location", + "type": "pickList", + "label": "ms-resource:loc.input.label.location", + "required": true, + "helpMarkDown": "ms-resource:loc.input.help.location", + "groupName": "AzureDetails", + "properties": { + "EditableOptions": "True" + }, + "visibleRule": "action = Create Or Update Resource Group || deploymentScope != Resource Group" + }, + { + "name": "templateLocation", + "type": "pickList", + "label": "ms-resource:loc.input.label.templateLocation", + "required": true, + "defaultValue": "Linked artifact", + "groupName": "Template", + "options": { + "Linked artifact": "Linked artifact", + "URL of the file": "URL of the file" + } + }, + { + "name": "csmFileLink", + "type": "string", + "label": "ms-resource:loc.input.label.csmFileLink", + "defaultValue": "", + "required": true, + "groupName": "Template", + "helpMarkDown": "ms-resource:loc.input.help.csmFileLink", + "visibleRule": "templateLocation = URL of the file" + }, + { + "name": "csmParametersFileLink", + "type": "string", + "label": "ms-resource:loc.input.label.csmParametersFileLink", + "defaultValue": "", + "required": false, + "groupName": "Template", + "helpMarkDown": "ms-resource:loc.input.help.csmParametersFileLink", + "visibleRule": " templateLocation = URL of the file" + }, + { + "name": "csmFile", + "type": "filePath", + "label": "ms-resource:loc.input.label.csmFile", + "defaultValue": "", + "required": true, + "groupName": "Template", + "visibleRule": " templateLocation = Linked artifact", + "helpMarkDown": "ms-resource:loc.input.help.csmFile" + }, + { + "name": "csmParametersFile", + "type": "filePath", + "label": "ms-resource:loc.input.label.csmParametersFile", + "defaultValue": "", + "required": false, + "groupName": "Template", + "helpMarkDown": "ms-resource:loc.input.help.csmParametersFile", + "visibleRule": " templateLocation = Linked artifact" + }, + { + "name": "overrideParameters", + "type": "multiLine", + "label": "ms-resource:loc.input.label.overrideParameters", + "defaultValue": "", + "required": false, + "groupName": "Template", + "helpMarkDown": "ms-resource:loc.input.help.overrideParameters", + "properties": { + "editorExtension": "ms.vss-services-azure.azurerg-parameters-grid" + } + }, + { + "name": "deploymentMode", + "type": "pickList", + "label": "ms-resource:loc.input.label.deploymentMode", + "defaultValue": "Incremental", + "required": true, + "groupName": "Template", + "helpMarkDown": "ms-resource:loc.input.help.deploymentMode", + "options": { + "Incremental": "Incremental", + "Complete": "Complete", + "Validation": "Validation only" + } + }, + { + "name": "deploymentName", + "type": "string", + "label": "ms-resource:loc.input.label.deploymentName", + "defaultValue": "", + "required": false, + "groupName": "Advanced", + "helpMarkDown": "ms-resource:loc.input.help.deploymentName" + }, + { + "name": "deploymentOutputs", + "type": "string", + "label": "ms-resource:loc.input.label.deploymentOutputs", + "required": false, + "defaultValue": "", + "groupName": "Advanced", + "helpMarkDown": "ms-resource:loc.input.help.deploymentOutputs" + }, + { + "name": "addSpnToEnvironment", + "type": "boolean", + "label": "ms-resource:loc.input.label.addSpnToEnvironment", + "defaultValue": "false", + "required": false, + "helpMarkDown": "ms-resource:loc.input.help.addSpnToEnvironment", + "groupName": "Advanced" + } + ], + "dataSourceBindings": [ + { + "target": "subscriptionName", + "endpointId": "$(ConnectedServiceName)", + "dataSourceName": "AzureSubscriptions", + "resultTemplate": "{ \"Value\" : \"{{{subscriptionId}}}\", \"DisplayValue\" : \"{{{displayName}}} ({{{subscriptionId}}})\" }" + }, + { + "target": "resourceGroupName", + "endpointId": "$(ConnectedServiceName)", + "dataSourceName": "AzureResourceGroupsByExplicitSubscription", + "parameters": { + "subscriptionId": "$(subscriptionName)" + } + }, + { + "target": "location", + "endpointId": "$(ConnectedServiceName)", + "dataSourceName": "AzureLocationsByDeploymentScope", + "parameters": { + "subscriptionId": "$(subscriptionName)", + "deploymentScope": "$(deploymentScope)" + } + } + ], + "instanceNameFormat": "ms-resource:loc.instanceNameFormat", + "execution": { + "Node": { + "target": "main.js" + } + }, + "messages": { + "CheckResourceGroupExistence": "ms-resource:loc.messages.CheckResourceGroupExistence", + "ResourceGroupStatusFetchFailed": "ms-resource:loc.messages.ResourceGroupStatusFetchFailed", + "ResourceGroupStatus": "ms-resource:loc.messages.ResourceGroupStatus", + "ResourceGroupCreationFailed": "ms-resource:loc.messages.ResourceGroupCreationFailed", + "CreatingNewRG": "ms-resource:loc.messages.CreatingNewRG", + "CreatedRG": "ms-resource:loc.messages.CreatedRG", + "CreatingTemplateDeployment": "ms-resource:loc.messages.CreatingTemplateDeployment", + "TemplateParsingFailed": "ms-resource:loc.messages.TemplateParsingFailed", + "FileFetchFailed": "ms-resource:loc.messages.FileFetchFailed", + "ParametersFileParsingFailed": "ms-resource:loc.messages.ParametersFileParsingFailed", + "StartingDeployment": "ms-resource:loc.messages.StartingDeployment", + "CreateTemplateDeploymentSucceeded": "ms-resource:loc.messages.CreateTemplateDeploymentSucceeded", + "CreateTemplateDeploymentFailed": "ms-resource:loc.messages.CreateTemplateDeploymentFailed", + "ErrorsInYourDeployment": "ms-resource:loc.messages.ErrorsInYourDeployment", + "Details": "ms-resource:loc.messages.Details", + "ErrorType": "ms-resource:loc.messages.ErrorType", + "PolicyDefinitionName": "ms-resource:loc.messages.PolicyDefinitionName", + "PolicyAssignmentName": "ms-resource:loc.messages.PolicyAssignmentName", + "StartingValidation": "ms-resource:loc.messages.StartingValidation", + "ValidDeployment": "ms-resource:loc.messages.ValidDeployment", + "CreateTemplateDeploymentValidationFailed": "ms-resource:loc.messages.CreateTemplateDeploymentValidationFailed", + "DeletingResourceGroup": "ms-resource:loc.messages.DeletingResourceGroup", + "CouldNotDeletedResourceGroup": "ms-resource:loc.messages.CouldNotDeletedResourceGroup", + "DeletedResourceGroup": "ms-resource:loc.messages.DeletedResourceGroup", + "InvalidAction": "ms-resource:loc.messages.InvalidAction", + "ARGD_ConstructorFailed": "ms-resource:loc.messages.ARGD_ConstructorFailed", + "InvalidTemplateLocation": "ms-resource:loc.messages.InvalidTemplateLocation", + "EncodingNotSupported": "ms-resource:loc.messages.EncodingNotSupported", + "CouldNotDetectEncoding": "ms-resource:loc.messages.CouldNotDetectEncoding", + "DetectedFileEncoding": "ms-resource:loc.messages.DetectedFileEncoding", + "ErrorWhileParsingParameter": "ms-resource:loc.messages.ErrorWhileParsingParameter", + "TemplateFilePatternMatchingMoreThanOneFile": "ms-resource:loc.messages.TemplateFilePatternMatchingMoreThanOneFile", + "TemplateParameterFilePatternMatchingMoreThanOneFile": "ms-resource:loc.messages.TemplateParameterFilePatternMatchingMoreThanOneFile", + "TemplateFilePatternMatchingNoFile": "ms-resource:loc.messages.TemplateFilePatternMatchingNoFile", + "TemplateParameterFilePatternMatchingNoFile": "ms-resource:loc.messages.TemplateParameterFilePatternMatchingNoFile", + "ParametersPatternMatchesADirectoryInsteadOfAFile": "ms-resource:loc.messages.ParametersPatternMatchesADirectoryInsteadOfAFile", + "CsmFilePatternMatchesADirectoryInsteadOfAFile": "ms-resource:loc.messages.CsmFilePatternMatchesADirectoryInsteadOfAFile", + "AddedOutputVariable": "ms-resource:loc.messages.AddedOutputVariable", + "UnableToReadResponseBody": "ms-resource:loc.messages.UnableToReadResponseBody", + "MoreInformationOnAzurePortal": "ms-resource:loc.messages.MoreInformationOnAzurePortal", + "LogDeploymentName": "ms-resource:loc.messages.LogDeploymentName", + "ResourceGroupNameNotProvided": "ms-resource:loc.messages.ResourceGroupNameNotProvided", + "LocationNotProvided": "ms-resource:loc.messages.LocationNotProvided", + "ARMServiceConnectionScope": "ms-resource:loc.messages.ARMServiceConnectionScope" + } +} \ No newline at end of file diff --git a/Tasks/AzureResourceManagerTemplateDeploymentV3/tsconfig.json b/Tasks/AzureResourceManagerTemplateDeploymentV3/tsconfig.json new file mode 100644 index 000000000000..875bb90cd697 --- /dev/null +++ b/Tasks/AzureResourceManagerTemplateDeploymentV3/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "target": "ES6", + "module": "commonjs" + } +} diff --git a/make-options.json b/make-options.json index 90c60bada085..ed94593851c6 100644 --- a/make-options.json +++ b/make-options.json @@ -30,6 +30,7 @@ "AzurePowerShellV3", "AzurePowerShellV4", "AzureResourceGroupDeploymentV2", + "AzureResourceManagerTemplateDeploymentV3", "AzureRmWebAppDeploymentV3", "AzureRmWebAppDeploymentV4", "AzureWebAppV1",