Skip to content

Commit 8bd8271

Browse files
CadaciousSteven Cadyv-mohithgc
authored
AzureResourceManagerTemplateDeploymentV3 - Add .bicepparam support (#19402)
* add support for bicepparam * changes required for unit testing to succeed * handle for same name bicep and param file * final changes for unit testing * BuildConfigGen task with config Node20_229_2 * changes based on feedback, increase task version * set proper filePath for json processing * increase task version after sprint rollover * remove extra . from beginning of file extension --------- Co-authored-by: Steven Cady <[email protected]> Co-authored-by: Mohith <[email protected]>
1 parent 60a19ae commit 8bd8271

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+6285
-54
lines changed

Tasks/AzureResourceManagerTemplateDeploymentV3/Strings/resources.resjson/en-US/resources.resjson

+5-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"loc.helpMarkDown": "[Learn more about this task](https://aka.ms/armtaskreadme)",
44
"loc.description": "Deploy an Azure Resource Manager (ARM) template to all the deployment scopes",
55
"loc.instanceNameFormat": "ARM Template deployment: $(deploymentScope) scope",
6-
"loc.releaseNotes": "- Added support for deployment at all the deployment scopes.\n- Removed all the VM related actions.",
6+
"loc.releaseNotes": "- Added support for bicepparam.",
77
"loc.group.displayName.AzureDetails": "Azure Details",
88
"loc.group.displayName.Template": "Template",
99
"loc.group.displayName.Advanced": "Advanced",
@@ -27,7 +27,7 @@
2727
"loc.input.label.csmFile": "Template",
2828
"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. 'Linked artifact' also has support for Bicep files when the Azure CLI version > 2.20.0",
2929
"loc.input.label.csmParametersFile": "Template parameters",
30-
"loc.input.help.csmParametersFile": "Specify the path or a pattern pointing for the parameters file for the Azure Resource Manager template. 'Linked artifact' also has support for Bicep files when the Azure CLI version > 2.20.0",
30+
"loc.input.help.csmParametersFile": "Specify the path or a pattern pointing for the parameters file for the Azure Resource Manager template. 'Linked artifact' also has support for Bicep Param files when the Azure CLI version > 2.47.0",
3131
"loc.input.label.overrideParameters": "Override template parameters",
3232
"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, <br>–storageName fabrikam –adminUsername $(vmusername) -adminPassword $(password) –azureKeyVaultName $(fabrikamFibre).<br>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)\"<br>To override object type parameters use stringified JSON objects. For example, -options [\"option1\"] -map {\"key1\": \"value1\" }. ",
3333
"loc.input.label.deploymentMode": "Deployment mode",
@@ -99,5 +99,7 @@
9999
"loc.messages.LoginFailed": "Azure login failed: %s",
100100
"loc.messages.MSILoginFailed": "Azure login failed using Managed Service Identity: %s",
101101
"loc.messages.AuthSchemeNotSupported": "Auth Scheme %s is not supported",
102-
"loc.messages.ErrorInSettingUpSubscription": "Error in setting up subscription: %s"
102+
"loc.messages.ErrorInSettingUpSubscription": "Error in setting up subscription: %s",
103+
"loc.messages.BicepParamBuildFailed": "\"az bicep build-param\" failed. Error: %s",
104+
"loc.messages.IncompatibleAzureCLIVersionBicepParam": "Azure CLI version should be >= 2.47.0 to use .bicepparam file"
103105
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
param location string = 'eastasia'
22

3-
var storageAccountName_var = 'deepak2121'
3+
var storageAccountName = 'deepak2121'
44
var storageAccountType = 'Premium_LRS'
55

66
resource storageAccount 'Microsoft.Storage/storageAccounts@2021-01-01' = {
7-
name: toLower(take(storageAccountName_var, 24))
7+
name: toLower(take(storageAccountName, 24))
88
location: location
99
sku: {
1010
name: storageAccountType
@@ -15,4 +15,4 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2021-01-01' = {
1515
output storageAccount_Name string = storageAccount.name
1616
output storageAccount_Location string = storageAccount.location
1717
output storageAccount_SKUName string = storageAccount.sku.name
18-
output storageAccount_Kind string = storageAccount.kind
18+
output storageAccount_Kind string = storageAccount.kind
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
using 'CSMwithBicep.bicep'
2+
3+
param location = 'eastasia'

Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/L0.ts

+20
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,26 @@ describe('Azure Resource Manager Template Deployment', function () {
226226
}
227227
});
228228

229+
it('Successfully triggered createOrUpdate deployment using bicep file with bicepparam file', (done) => {
230+
let tp = path.join(__dirname, 'createOrUpdate.js');
231+
process.env["csmFile"] = "CSMwithBicep.bicep";
232+
process.env["csmParametersFile"] = "CSMwithBicep.bicepparam";
233+
process.env["deploymentOutputs"] = "someVar";
234+
let tr = new ttm.MockTestRunner(tp);
235+
tr.run();
236+
try {
237+
assert(tr.succeeded, "Should have succeeded");
238+
assert(tr.stdout.indexOf("deployments.createOrUpdate is called") > 0, "deployments.createOrUpdate function should have been called from azure-sdk");
239+
assert(tr.stdout.indexOf("##vso[task.setvariable variable=someVar;]") >= 0, "deploymentsOutput should have been updated");
240+
done();
241+
}
242+
catch (error) {
243+
console.log("STDERR", tr.stderr);
244+
console.log("STDOUT", tr.stdout);
245+
done(error);
246+
}
247+
});
248+
229249
// it('createOrUpdate deployment should fail when bicep file contains error', (done) => {
230250
// let tp = path.join(__dirname, 'createOrUpdate.js');
231251
// process.env["csmFile"] = "CSMwithBicepWithError.bicep";

Tasks/AzureResourceManagerTemplateDeploymentV3/Tests/createOrUpdate.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@ process.env["ENDPOINT_AUTH_PARAMETER_AzureRM_AUTHENTICATIONTYPE"] = "key";
3333

3434
var CSMJson = path.join(__dirname, "CSM.json");
3535
var CSMBicep = path.join(__dirname, "CSMwithBicep.bicep");
36+
var CSMBicepParam = path.join(__dirname, "CSMwithBicep.bicepparam");
3637
var CSMBicepWithWarning = path.join(__dirname, "CSMwithBicepWithWarning.bicep");
3738
var CSMBicepWithError = path.join(__dirname, "CSMwithBicepWithError.bicep");
3839
var CSMwithComments = path.join(__dirname, "CSMwithComments.json");
3940
var defaults = path.join(__dirname, "defaults.json");
4041
var faultyCSM = path.join(__dirname, "faultyCSM.json");
4142
var bicepbuildCmd = `az bicep build --file ${path.join(__dirname, "CSMwithBicep.bicep")}`;
43+
var bicepparambuildCmd = `az bicep build-params --file ${path.join(__dirname, "CSMwithBicep.bicepparam")} --outfile ${path.join(__dirname, "CSMwithBicep.parameters.json")}`;
4244
var bicepbuildwithWarning = `az bicep build --file ${path.join(__dirname, "CSMwithBicepWithWarning.bicep")}`;
4345
var azloginCommand = `az login --service-principal -u "id" --password="key" --tenant "tenant" --allow-no-subscriptions`;
4446
var azaccountSet = `az account set --subscription "sId"`;
@@ -50,6 +52,7 @@ const successExec = {
5052
"stdout": "Executed Successfully"
5153
}
5254
exec[bicepbuildCmd] = successExec;
55+
exec[bicepparambuildCmd] = successExec;
5356
exec[bicepbuildwithWarning] = successExec;
5457
exec[azloginCommand] = successExec;
5558
exec[azaccountSet] = successExec;
@@ -66,6 +69,7 @@ let a: ma.TaskLibAnswers = <ma.TaskLibAnswers>{
6669
"findMatch": {
6770
"CSM.json": [CSMJson],
6871
"CSMwithBicep.bicep": [CSMBicep],
72+
"CSMwithBicep.bicepparam": [CSMBicepParam],
6973
"CSMwithBicepWithWarning.bicep": [CSMBicepWithWarning],
7074
"CSMwithBicepWithError.bicep": [CSMBicepWithError],
7175
"CSMwithComments.json": [CSMwithComments],
@@ -85,10 +89,14 @@ tr.registerMock('azure-pipelines-tasks-azure-arm-rest/azure-arm-resource', requi
8589

8690
const fsClone = Object.assign({}, fs);
8791
fsClone.readFileSync = function(fileName: string): Buffer {
88-
if (fileName.indexOf("CSMwithBicep") >= 0) {
92+
if (fileName.indexOf("CSMwithBicep.json") >= 0 || fileName.indexOf("CSMwithBicepWithWarning.json") >= 0) {
8993
const filePath = fileName.replace('.json', '.bicep');
9094
cpExec(`az bicep build --file ${filePath}`);
9195
}
96+
else if (fileName.indexOf("CSMwithBicep.parameters.json") >= 0) {
97+
const filePath = fileName.replace('.parameters.json', '.bicepparam');
98+
cpExec(`az bicep build-params --file ${filePath} --outfile ${fileName}`);
99+
}
92100
var buffer = fs.readFileSync(fileName);
93101
return buffer;
94102
}

Tasks/AzureResourceManagerTemplateDeploymentV3/operations/Utils.ts

+44-11
Original file line numberDiff line numberDiff line change
@@ -427,23 +427,34 @@ class Utils {
427427

428428
private static async getFilePathForLinkedArtifact(filePath: string, taskParameters: armDeployTaskParameters.TaskParameters): Promise<string> {
429429
var filePathExtension: string = filePath.split('.').pop();
430-
if(filePathExtension === 'bicep'){
430+
if(filePathExtension.startsWith('bicep')){
431431
let azcliversion = await this.getAzureCliVersion()
432432
if(parseFloat(azcliversion)){
433-
if(this.isBicepAvailable(azcliversion)){
433+
if(this.isBicepAvailable(azcliversion, filePathExtension)){
434434
setAzureCloudBasedOnServiceEndpoint(taskParameters.connectedService);
435435
await loginAzureRM(taskParameters.connectedService);
436436
await this.execBicepBuild(filePath)
437-
filePath = filePath.replace('.bicep', '.json')
438-
this.cleanupFileList.push(filePath)
437+
if(filePathExtension === 'bicep'){
438+
filePath = filePath.replace('.bicep', '.json')
439+
}
440+
else{
441+
filePath = filePath.replace('.bicepparam', '.parameters.json')
442+
}
439443
await this.logoutAzure();
440444
}else{
441-
throw new Error(tl.loc("IncompatibleAzureCLIVersion"));
445+
//Maintain backwards compatibility for runs that are not using bicep param and do not require higher version
446+
if(filePathExtension === 'bicep'){
447+
throw new Error(tl.loc("IncompatibleAzureCLIVersion"));
448+
}
449+
else{
450+
throw new Error(tl.loc("IncompatibleAzureCLIVersionBicepParam"));
451+
}
442452
}
443453
}else{
444454
throw new Error(tl.loc("AzureCLINotFound"));
445455
}
446456
}
457+
447458
return filePath
448459
}
449460

@@ -463,10 +474,28 @@ class Utils {
463474
}
464475

465476
private static async execBicepBuild(filePath): Promise<void> {
466-
const result: IExecSyncResult = tl.execSync("az", `bicep build --file ${filePath}`);
467-
if(result && result.code !== 0){
468-
throw new Error(tl.loc("BicepBuildFailed", result.stderr));
477+
var filePathExtension: string = filePath.split('.').pop();
478+
var finalPathExtension: string = ".json"
479+
480+
if(filePathExtension === 'bicep'){
481+
const result: IExecSyncResult = tl.execSync("az", `bicep build --file ${filePath}`);
482+
if(result && result.code !== 0){
483+
throw new Error(tl.loc("BicepBuildFailed", result.stderr));
484+
}
485+
}
486+
else{
487+
var fileName: string = filePath.split(path.sep).pop().split('.')[0];
488+
var fileDir: string = filePath.replace(path.sep + fileName +'.bicepparam', '')
489+
finalPathExtension = ".parameters.json"
490+
491+
//Using --outfile to avoid overwriting primary bicep file in the case bicep and param file have the the same file name.
492+
const result: IExecSyncResult = tl.execSync("az", `bicep build-params --file ${filePath} --outfile ${path.join(fileDir, fileName + finalPathExtension)}`);
493+
if(result && result.code !== 0){
494+
throw new Error(tl.loc("BicepParamBuildFailed", result.stderr));
495+
}
469496
}
497+
498+
this.cleanupFileList.push(filePath.replace('.' + filePathExtension, finalPathExtension))
470499
}
471500

472501
private static async logoutAzure() {
@@ -476,11 +505,15 @@ class Utils {
476505
}
477506
}
478507

479-
private static isBicepAvailable(azcliversion): Boolean{
508+
private static isBicepAvailable(azcliversion,extension): Boolean{
480509
let majorVersion = azcliversion.split('.')[0]
481510
let minorVersion = azcliversion.split('.')[1]
482-
// Support Bicep was introduced in az-cli 2.20.0
483-
if((majorVersion == 2 && minorVersion >= 20) || majorVersion > 2){
511+
// Support for Bicep format was introduced in az-cli 2.20.0
512+
if(((majorVersion == 2 && minorVersion >= 20) && extension === 'bicep') || majorVersion > 2){
513+
return true
514+
}
515+
// Support for Bicep Param format was introduced in az-cli 2.47.0
516+
else if(((majorVersion == 2 && minorVersion >= 47) && extension === 'bicepparam') || majorVersion > 2){
484517
return true
485518
}
486519
return false

Tasks/AzureResourceManagerTemplateDeploymentV3/task.json

+5-3
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
"helpUrl": "https://docs.microsoft.com/azure/devops/pipelines/tasks/deploy/azure-resource-group-deployment",
77
"helpMarkDown": "[Learn more about this task](https://aka.ms/armtaskreadme)",
88
"category": "Deploy",
9-
"releaseNotes": "- Added support for deployment at all the deployment scopes.\n- Removed all the VM related actions.",
9+
"releaseNotes": "- Added support for bicepparam.",
1010
"visibility": [
1111
"Build",
1212
"Release"
1313
],
1414
"author": "Microsoft Corporation",
1515
"version": {
1616
"Major": 3,
17-
"Minor": 231,
17+
"Minor": 235,
1818
"Patch": 0
1919
},
2020
"demands": [],
@@ -331,6 +331,8 @@
331331
"LoginFailed": "Azure login failed: %s",
332332
"MSILoginFailed": "Azure login failed using Managed Service Identity: %s",
333333
"AuthSchemeNotSupported": "Auth Scheme %s is not supported",
334-
"ErrorInSettingUpSubscription": "Error in setting up subscription: %s"
334+
"ErrorInSettingUpSubscription": "Error in setting up subscription: %s",
335+
"BicepParamBuildFailed": "\"az bicep build-param\" failed. Error: %s",
336+
"IncompatibleAzureCLIVersionBicepParam": "Azure CLI version should be >= 2.47.0 to use .bicepparam file"
335337
}
336338
}

Tasks/AzureResourceManagerTemplateDeploymentV3/task.loc.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"author": "Microsoft Corporation",
1515
"version": {
1616
"Major": 3,
17-
"Minor": 231,
17+
"Minor": 235,
1818
"Patch": 0
1919
},
2020
"demands": [],
@@ -331,6 +331,8 @@
331331
"LoginFailed": "ms-resource:loc.messages.LoginFailed",
332332
"MSILoginFailed": "ms-resource:loc.messages.MSILoginFailed",
333333
"AuthSchemeNotSupported": "ms-resource:loc.messages.AuthSchemeNotSupported",
334-
"ErrorInSettingUpSubscription": "ms-resource:loc.messages.ErrorInSettingUpSubscription"
334+
"ErrorInSettingUpSubscription": "ms-resource:loc.messages.ErrorInSettingUpSubscription",
335+
"BicepParamBuildFailed": "ms-resource:loc.messages.BicepParamBuildFailed",
336+
"IncompatibleAzureCLIVersionBicepParam": "ms-resource:loc.messages.IncompatibleAzureCLIVersionBicepParam"
335337
}
336338
}
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Default|3.231.0
2-
Node20_229_2|3.231.2
1+
Default|3.235.0
2+
Node20_229_2|3.235.1

0 commit comments

Comments
 (0)