Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mark parameter modifiers as deprecated and update spec #1693

Merged
merged 8 commits into from
Mar 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 64 additions & 60 deletions docs/spec/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,95 +13,99 @@ param myObject object
param myArray array
```

A parameter cannot have the same name as a [variable](./variables.md), [resource](./resources.md), [output](./outputs.md) or another parameter in the same scope.

## Secure parameters
If you are familiar with ARM template parameters, you will notice a conspicuous absense of `secureString` and `secureObject` types. In this language, these types are implemented as modifiers.

The following declarations will compile into a `secureString` and `secureObject` parameters, respectively.
## Default value
Default values can be declared as follows:
```
param myPassword string {
secure: true
}

param mySuperSecretObject object {
secure: true
}
param myParam string = 'my default value'
```
## Allowed Values
You can constrain which values are allowed using the `allowed` modifier:

You may use [expressions](./expressions.md) with the `default` modifier. Here is an example of a location parameter whose value defaults to the location of the current resource group if the parameter is not specified during the deployment:
```
param myEnum string {
allowed: [
'one'
'two'
]
}
param myParam string = resourceGroup().location
```

The constraint will be evaluated at deployment time of the compiled template.
A parameter cannot have the same name as a [variable](./variables.md), [resource](./resources.md), [output](./outputs.md) or another parameter in the same scope.

## Declaration with decorators
Decorators provide a way to attach constrains and metadata to a parameter. Decorators are placed above the parameter declaration to be decorated. They use the form @expression, where expression must be a function call:

## Default value
Default values can be declared as follows:
```
param myParam string = 'my default value'
@expression
param myParam string
```

If you need to combine a default value with other identifiers, you may also use the following syntax to achieve the same:
```
param myParam string {
default: 'my default value'
}
### Secure parameters
If you are familiar with ARM template parameters, you will notice a conspicuous absence of `secureString` and `secureObject` types. In this language, these types are annotated with the `@secure` decorator.

The following declarations will compile into a `secureString` and `secureObject` parameters, respectively.
```
@secure()
param myPassword string

You may use [expressions](./expressions.md) with the `default` modifier. (All other modifiers require a constant literal.) Here is an example of a location parameter whose value defaults to the location of the current resource group if the parameter is not specified during the deployment:
@secure()
param mySuperSecretObject object
```
### Allowed Values
You can constrain which values are allowed using the `@allowed` decorator:
```
param myParam string {
default: resourceGroup().location
}
@allowed([
'one'
'two'
])
param myEnum string
```

## String and array length constraint
The constraint will be evaluated at deployment time of the compiled template.

### String and array length constraint
Parameters of type `string` and `array` can have length constraints. The following declares a storage account name parameter of type strings whose length can only be between 3-24 characters (inclusive).
```
param storageAccountName string {
minLength: 3
maxLength: 24
}
@minLength(3)
@maxLength(24)
param storageAccountName string
```

The length constraint is evaluated at compiled template deployment time.

## Integer value constraint
### Integer value constraint
Integer parameters can also have a value constraint. These are expressed as follows:
```
param month int {
minValue: 1
maxValue: 12
}
@minValue(1)
@maxValue(12)
param month int
```

The value constraint is evaluated at compiled template deployment time.

## Description
### Metadata
Parameters of any type can have metadata. The following example shows how to attach a metadata object to a parameter:
```
@metadata({
author: 'Example Name'
})
param myParam string
```

### Description
Parameters of any type can have a description associated with them. This looks like the following:
```
param myObject object {
metadata: {
description: "There are many like this, but this object is mine."
}
}
@description('There are many like this, but this object is mine.')
param myObject object
```

The `@metadata` decorator can be used to achieve the same goal, but it is a bit more verbose:
```
@metadata({
description: 'There are many like this, but this object is mine.'
})
param myObject object
```

## Combined modifiers
If applicable to the parameter type, multiple modifiers can be combined together. The following is an example of this:
### Combined decorators
If applicable to the parameter type, multiple decorators can be combined together. The following is an example of this:
```
param storageAccountName string {
minLength: 3
maxLength: 24
default: concat(uniqueString(resourceGroup().id), 'sa')
metadata: {
description: "Name of the storage account"
}
}
@minLength(3)
@maxLength(24)
@description('Name of the storage account')
param storageAccountName string = concat(uniqueString(resourceGroup().id), 'sa')
```
27 changes: 20 additions & 7 deletions src/Bicep.Cli.IntegrationTests/ProgramTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,18 @@
using System.IO;
using System.Linq;
using Bicep.Cli.UnitTests;
using Bicep.Core.Extensions;
using Bicep.Core.FileSystem;
using Bicep.Core.Samples;
using Bicep.Core.Semantics;
using Bicep.Core.Syntax;
using Bicep.Core.Text;
using Bicep.Core.UnitTests.Assertions;
using Bicep.Core.UnitTests.Json;
using Bicep.Core.UnitTests;
using Bicep.Core.UnitTests.Assertions;
using Bicep.Core.UnitTests.Utils;
using Bicep.Core.Workspaces;
using FluentAssertions;
using FluentAssertions.Execution;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Bicep.Cli.IntegrationTests
Expand Down Expand Up @@ -132,7 +129,7 @@ public void BuildSingleFileShouldProduceExpectedTemplate(DataSet dataSet)
{
result.Should().Be(0);
output.Should().BeEmpty();
error.Should().BeEmpty();
AssertEmptyOrDeprecatedError(error, dataSet.Name);
}

var compiledFilePath = Path.Combine(outputDirectory, DataSet.TestFileMainCompiled);
Expand Down Expand Up @@ -163,8 +160,8 @@ public void BuildSingleFileToStdOutShouldProduceExpectedTemplate(DataSet dataSet
using (new AssertionScope())
{
result.Should().Be(0);
error.Should().BeEmpty();
output.Should().NotBeEmpty();
AssertEmptyOrDeprecatedError(error, dataSet.Name);
}

var compiledFilePath = Path.Combine(outputDirectory, DataSet.TestFileMainCompiled);
Expand Down Expand Up @@ -337,7 +334,7 @@ public void LockedOutputFileShouldProduceExpectedError()
}
}

private IEnumerable<string> GetAllDiagnostics(string bicepFilePath)
private static IEnumerable<string> GetAllDiagnostics(string bicepFilePath)
{
var syntaxTreeGrouping = SyntaxTreeGroupingBuilder.Build(new FileResolver(), new Workspace(), PathHelper.FilePathToFileUrl(bicepFilePath));
var compilation = new Compilation(TestResourceTypeProvider.Create(), syntaxTreeGrouping);
Expand All @@ -364,6 +361,22 @@ private static IEnumerable<object[]> GetInvalidDataSets() => DataSets
.AllDataSets
.Where(ds => ds.IsValid == false)
.ToDynamicTestData();

private static void AssertEmptyOrDeprecatedError(string error, string dataSetName)
{
if (dataSetName == "Parameters_LF" || dataSetName == "Parameters_CRLF")
{
// TODO: remove this branch when the support of parameter modifiers is dropped.
foreach(var line in error.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries))
{
line.Should().Contain("BCP161");
}
}
else
{
error.Should().BeEmpty();
}
}
}
}

10 changes: 4 additions & 6 deletions src/Bicep.Core.IntegrationTests/Emit/TemplateEmitterTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
Expand All @@ -11,12 +10,11 @@
using Bicep.Core.Samples;
using Bicep.Core.Semantics;
using Bicep.Core.Syntax;
using Bicep.Core.UnitTests.Assertions;
using Bicep.Core.UnitTests;
using Bicep.Core.UnitTests.Assertions;
using Bicep.Core.UnitTests.Utils;
using Bicep.Core.Workspaces;
using FluentAssertions;
using FluentAssertions.Execution;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
Expand All @@ -40,7 +38,7 @@ public void ValidBicep_TemplateEmiterShouldProduceExpectedTemplate(DataSet dataS
// emitting the template should be successful
var result = this.EmitTemplate(SyntaxTreeGroupingBuilder.Build(new FileResolver(), new Workspace(), PathHelper.FilePathToFileUrl(bicepFilePath)), compiledFilePath, BicepTestConstants.DevAssemblyFileVersion);
result.Status.Should().Be(EmitStatus.Succeeded);
result.Diagnostics.Should().BeEmpty();
result.Diagnostics.Should().BeEmptyOrContainDeprecatedDiagnosticOnly();

var actual = JToken.Parse(File.ReadAllText(compiledFilePath));

Expand Down Expand Up @@ -79,7 +77,7 @@ public void ValidBicepTextWriter_TemplateEmiterShouldProduceExpectedTemplate(Dat

// emitting the template should be successful
var result = this.EmitTemplate(SyntaxTreeGroupingBuilder.Build(new FileResolver(), new Workspace(), PathHelper.FilePathToFileUrl(bicepFilePath)), memoryStream, BicepTestConstants.DevAssemblyFileVersion);
result.Diagnostics.Should().BeEmpty();
result.Diagnostics.Should().BeEmptyOrContainDeprecatedDiagnosticOnly();
result.Status.Should().Be(EmitStatus.Succeeded);

// normalizing the formatting in case there are differences in indentation
Expand All @@ -104,7 +102,7 @@ public void ValidBicepTextWriter_TemplateEmiterTemplateHashCheck(DataSet dataSet

// emitting the template should be successful
var result = this.EmitTemplate(SyntaxTreeGroupingBuilder.Build(new FileResolver(), new Workspace(), PathHelper.FilePathToFileUrl(bicepFilePath)), memoryStream, ThisAssembly.AssemblyFileVersion);
result.Diagnostics.Should().BeEmpty();
result.Diagnostics.Should().BeEmptyOrContainDeprecatedDiagnosticOnly();
result.Status.Should().Be(EmitStatus.Succeeded);

var actual = JToken.ReadFrom(new JsonTextReader(new StreamReader(new MemoryStream(memoryStream.ToArray()))));
Expand Down
31 changes: 15 additions & 16 deletions src/Bicep.Core.Samples/Files/AKS_LF/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,25 @@
param dnsPrefix string
param linuxAdminUsername string
param sshRSAPublicKey string
param servcePrincipalClientId string {
secure: true
}
param servicePrincipalClientSecret string {
secure: true
}

@secure()
param servcePrincipalClientId string

@secure()
param servicePrincipalClientSecret string

// optional params
param clusterName string = 'aks101cluster'
param location string = resourceGroup().location
param osDiskSizeGB int {
default: 0
minValue: 0
maxValue: 1023
}
param agentCount int {
default: 3
minValue: 1
maxValue: 50
}

@minValue(0)
@maxValue(1023)
param osDiskSizeGB int = 0

@minValue(1)
@maxValue(50)
param agentCount int = 3

param agentVMSize string = 'Standard_DS2_v2'
// osType was a defaultValue with only one allowedValue, which seems strange?, could be a good TTK test

Expand Down
31 changes: 15 additions & 16 deletions src/Bicep.Core.Samples/Files/AKS_LF/main.diagnostics.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,25 @@
param dnsPrefix string
param linuxAdminUsername string
param sshRSAPublicKey string
param servcePrincipalClientId string {
secure: true
}
param servicePrincipalClientSecret string {
secure: true
}

@secure()
param servcePrincipalClientId string

@secure()
param servicePrincipalClientSecret string

// optional params
param clusterName string = 'aks101cluster'
param location string = resourceGroup().location
param osDiskSizeGB int {
default: 0
minValue: 0
maxValue: 1023
}
param agentCount int {
default: 3
minValue: 1
maxValue: 50
}

@minValue(0)
@maxValue(1023)
param osDiskSizeGB int = 0

@minValue(1)
@maxValue(50)
param agentCount int = 3

param agentVMSize string = 'Standard_DS2_v2'
// osType was a defaultValue with only one allowedValue, which seems strange?, could be a good TTK test

Expand Down
Loading