Skip to content

Commit f494a9e

Browse files
authored
Merge pull request #1 from nnellans/feature/updates
Feature/updates
2 parents 977a335 + 89f9164 commit f494a9e

File tree

4 files changed

+278
-81
lines changed

4 files changed

+278
-81
lines changed

README.md

+232-35
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
# Bicep Files & File Names
1515
Bicep files use a `.bicep` file extension and are written using their own custom domain-specific language (DSL).
1616

17-
If you're accustomed to Terraform, you will see that Bicep works differently when it comes to deploying code. Terraform will combine every `.tf` file in the current directory and deploy all of them at the same time. Whereas Bicep will deploy one main `.bicep` file per deployment. It is suggested to name this file `main.bicep`
17+
If you're accustomed to Terraform, you will see that Bicep works differently when it comes to deploying code. Terraform will combine every `.tf` file in the current directory and deploy them all at the same time. Whereas Bicep will deploy one main `.bicep` file per deployment. It is suggested to name this file `main.bicep`
1818

1919
If you are storing parameters values in a separate parameters JSON file, it is common practice to use the name of the Bicep file and just add the word "parameters" like shown below. If you are using the newer Bicep parameter format, then just use the name of the Bicep file with the extension of `.bicepparam`. Support for `.bicepparam` files requires Bicep v0.18.4 or later.
2020

@@ -87,7 +87,7 @@ resource exampleStorageAccount 'Microsoft.Storage/storageAccounts@2021-04-01' =
8787
- You can use more than one decorator for each parameter definition
8888
- It's good practice to specify the `minLength` and `maxLength` decorators for parameters that control resource naming. These limitations help avoid errors later during deployment
8989
- For integers you can specify `minValue` and `maxValue` decorators, instead
90-
- It's good practice to provide the `description` decorator for all of your parameters. Try to make them helpful
90+
- It's good practice to specify the `description` decorator for all of your parameters. Try to make them helpful
9191
- The `allowed` decorator can be used to provide allowed values in an array. If the value doesn't match, then the deployment fails
9292
- Use this sparingly, as Azure makes changes frequently to things like SKUs and sizes, so you don't want to have an allowed list that is out of date
9393
- The `metadata` decorator is an object that can contain properties of any name and type. Use this for info that you don't want to put into the `description` decorator
@@ -130,7 +130,7 @@ param someName array = [ 'one', 'two', 'three' ]
130130
```
131131
- In single-line, a comma after the last value is supported, but not required
132132
- The data types in an array do NOT have to match, as each item is represented by the 'any' type
133-
- Bicep arrays are zero-based, so `exampleArrayParameter[0] = 'value1'`
133+
- Bicep arrays are zero-based, so using the example above `someName[0] = 'one'`
134134

135135
### Bool
136136
- Simply use either `true` or `false` with no quotation marks
@@ -506,16 +506,74 @@ az deployment group show -g <rgName> -n <deploymentName> --query properties.outp
506506

507507
# Other Topics
508508

509+
- [Parameter Files](README.md#parameter-files)
509510
- [Conditions (If)](README.md#conditions-if)
510511
- [Loops](README.md#loops)
511512
- Miscellaneous
512513
- [Comments](README.md#comments)
513-
- [Interpolation](README.md#interpolation)
514+
- [String Interpolation](README.md#string-interpolation)
514515
- [Ternary Operator](README.md#ternary-operator)
515516
- [Functions](README.md#functions)
517+
- [Import / Export](README.md#import--export)
516518

517519
---
518520

521+
# Parameter Files
522+
523+
Instead of storing parameter values directly in your `.bicep` file, you can store the values externally in a `.bicepparam` or `.json` file. Then, you'd pass this parameter file, along with the `.bicep` file, to your deployment.
524+
525+
> [!NOTE]
526+
> This guide is only going to cover the newer `.bicepparam` files. If you'd like to know more about the older `.json` parameter files, then please reference [the documentation](https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/parameter-files).
527+
528+
Format of a `.bicepparam file`
529+
```bicep
530+
// the using statement
531+
using 'something'
532+
533+
// optional variables
534+
var varName1 = value1
535+
var varName2 = value2
536+
537+
// parameter values
538+
param parName1 = value1
539+
param parName2 = readEnvironmentVariable('someEnvVar')
540+
param parName3 = toLower(value3)
541+
param parName4 = az.getSecret('subscriptionId', 'resourceGroupName', 'keyvaultName', 'secretName', 'secretVersion')
542+
```
543+
544+
Each `.bicepparam` file is tied to a particular `.bicep` file. This relationship is defined by the `using` statement. There are multiple options for defining the `using` statement, see below for more.
545+
- Support for ARM Templates, Bicep Registries, and Template Specs was added in Bicep v0.22.6
546+
547+
```bicep
548+
// a regular bicep file or arm template
549+
using 'path/to/file.bicep'
550+
using 'path/to/file.json'
551+
552+
// a module from the public bicep registry
553+
using 'br/public:path:tag'
554+
555+
// a module from a private bicep registry
556+
using 'br:registryName.azurecr.io/bicep/path:tag'
557+
using 'br/aliasName:path:tag'
558+
559+
// a template spec
560+
using 'ts:subscriptionId/resourceGroupName/specName:tag'
561+
using 'ts/aliasName:specName:tag'
562+
563+
// NOT tied to anything
564+
using none
565+
```
566+
567+
Starting with Bicep v0.21.1 you can define optional Variables in your `.bicepparam` files.
568+
569+
You can use expressions in the value of each parameter.
570+
- Use the `readEnvironmentVariable` function to pull a value from an environment variable.
571+
- Don't store sensitive values in your parameter files. Instead, use the `az.getSecret` function to pull the value from Key Vault.
572+
- The `az.getSecret` function can only pull secrets from Key Vault.
573+
- The `az.getSecret` function can only be used in a `param` value
574+
- The `az.getSecret` function only supports params that have the `@secure()` decorator
575+
- By default, it will pull the latest version of the secret, unless you specify the `secretVersion` parameter
576+
519577
# Conditions (If)
520578
You can deploy a resource only if a certain condition is met, otherwise the resource will not be deployed
521579

@@ -606,7 +664,7 @@ multi-line comment
606664
*/
607665
```
608666

609-
## Interpolation
667+
## String Interpolation
610668
- All strings in Bicep support interpolation
611669
- To inject an expression surround it by `${` and `}`
612670

@@ -630,19 +688,45 @@ The true or false values can be of any data type: string, integer, boolean, obje
630688

631689
Bicep has a large assortment of functions that can be used in your template. Check out the [officials docs](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions) for more information about all of the available Functions and their instructions.
632690

691+
### User-defined Functions
692+
- Support for User-defined Functions requires Bicep v0.26.54 or later
693+
- Allows you to create and use your own custom functions within a Bicep file
694+
- Great for when you have complicated expressions that are used repeatedly in your Bicep files
695+
- They can be nested, you can call a User-defined Function from another User-defined function
696+
- They support custom User-defined Data Types
697+
- Some limitations:
698+
- Can't access variables
699+
- Can only use parameters that are defined in the function
700+
- Parameters defined in the function can't have default values
701+
- Can't use the `reference` or `list` functions
702+
- [Read the docs](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/user-defined-functions) for more information on User-defined Functions
703+
704+
```bicep
705+
// create a user-defined function
706+
func functionName (argName dataType, argName dataType, ...) functionDataType => expression
707+
708+
// first, define the functionName that you want to give to this user-defined function
709+
// then, define any arguments that the function uses, specify a name and a data type for each argument
710+
// then, define the data type of the function's return value
711+
// finally, define what value the function will return by creating a custom expression that uses the arguments
712+
```
713+
633714
### Lambda Expressions
634-
- Lambda Expressions are supported starting with Bicep v0.10.61.
635-
- Lambda Expressions can only be used as arguments on 5 specific functions: `filter`, `map`, `reduce`, `sort`, and `toObject`. See below for examples of each one
715+
- Lambda Expressions can only be used as arguments on the following specific functions:
716+
- `filter()`, `map()`, `reduce()`, `sort()` - Supported with Bicep v0.10.61 onward
717+
- `toObject()` - Supported with Bicep v0.14.6 onward
718+
- `groupBy()`, `mapValues()` - Supported with Bicep v0.27.1 onward
636719
- The general format of a Lambda Expression is `lambdaVariable => lambdaExpression`.
637720
- [Read the docs](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions-lambda) for more information and examples for Lamba Expressions.
638721

639722
Example: `filter()`
640723

641724
```bicep
725+
filter(inputArray, lambdaExpression)
642726
// input: array
643-
// lambaExpression: run a test against each element of the array
727+
// lambaExpression: expression/test to run against each element of the array
728+
// - Supports an optional index as of Bicep v0.27.1
644729
// output: array (containing only elements that passed the test)
645-
filter(inputArray, lambdaExpression)
646730
647731
// example
648732
var inputArray = [
@@ -657,17 +741,42 @@ var inputArray = [
657741
]
658742
659743
output someOutput array = filter(inputArray, item => item.age > 15)
660-
// This retuns only elements of the array that have an age greater than 15,
661-
// so in our example only 1 of the 2 elements will be returned
744+
// This returns only elements of the array that have an age value greater than 15,
745+
someOutput = [
746+
{
747+
name: 'Reba'
748+
age: 24
749+
}
750+
]
751+
```
752+
753+
Example: `groupBy()`
754+
755+
```bicep
756+
groupBy(inputArray, lambdaExpression)
757+
// input: array
758+
// lambdaExpression: the expression used to group the array elements
759+
// output: object (containing the grouped elements)
760+
761+
//example
762+
var inputArray = ['Reba', 'Rodney', 'Garth', 'Gary']
763+
764+
output someOutput object = groupBy(inputArray, item => substring(item, 0, 1))
765+
// This returns an object which groups the array elements by their first character
766+
someOutput = {
767+
R: ['Reba', 'Rodney']
768+
G: ['Garth', 'Gary']
769+
}
662770
```
663771

664772
Example: `map()`
665773

666774
```bicep
775+
map(inputArray, lambdaExpression)
667776
// input: array
668777
// lambaExpression: whatever manipulation you want
778+
// - Supports an optional index as of Bicep v0.27.1
669779
// output: array (containing your manipulated elements)
670-
map(inputArray, lambdaExpression)
671780
672781
// example
673782
var inputArray = [
@@ -683,30 +792,66 @@ var inputArray = [
683792
684793
output someOutput1 array = map(inputArray, item => item.name)
685794
// This returns an array containing just the values of each name:
686-
// [ 'Reba', 'Garth' ]
795+
someOutput1 = [
796+
'Reba'
797+
'Garth'
798+
]
687799
688800
output someOutput2 array = map(inputArray, item => 'Hello ${item.name}!')
689801
// This returns an array which concatenates text to each name:
690-
// [ 'Hello Reba!', 'Hello Garth!' ]
802+
someOutput2 = [
803+
'Hello Reba!'
804+
'Hello Garth!'
805+
]
806+
```
807+
808+
Example: `mapValues()`
809+
810+
```bicep
811+
mapValues(inputObject, lambdaExpression)
812+
// input: object
813+
// lambdaExpression: the expression used to modify each value
814+
// output: object (containing modified values)
815+
816+
// example
817+
var inputObject = {
818+
something: 'foo'
819+
anotherthing: 'bar'
820+
}
821+
822+
output someOutput object = mapValues(inputObject, item => toUpper(item))
823+
// This returns the same object, but with modified values. In this case, the values are converted to uppercase:
824+
someOutput = {
825+
something: 'FOO'
826+
anotherthing: 'BAR'
827+
}
691828
```
692829

693830
Example: `reduce()`
694831

695832
```bicep
833+
reduce(inputArray, initialValue, lambdaExpression)
696834
// input: array
697-
// initialValue:
698-
// lambdaExpression:
835+
// initialValue: the initial starting value for comparison
836+
// lambdaExpression: expression used to aggregate the current value with the next value
837+
// - Supports an optional index as of Bicep v0.27.1
699838
// output: any
700-
reduce(inputArray, initialValue, lambdaExpression)
839+
840+
var inputArray = [5, 3, 2, 8]
841+
842+
output someOutput int = reduce(inputArray, 0, (currentItem, nextItem) => currentItem + nextItem)
843+
// This returns an integer which is the result of adding each item in the array to the next item, starting with 0
844+
// For example: ((((0 + 5) + 3) + 2) + 8)
845+
someOutput = 18
701846
```
702847

703848
Example: `sort()`
704849

705850
```bicep
851+
sort(inputArray, lambdaExpression)
706852
// input: array
707853
// lambdaExpression: an expression that compares one array element to another
708854
// output: array (elements are sorted per your expression)
709-
sort(inputArray, lambdaExpression)
710855
711856
// example
712857
var inputArray = [
@@ -726,16 +871,30 @@ var inputArray = [
726871
727872
output someOutput array = sort(inputArray, (item1, item2) => item1.age < item2.age)
728873
// This returns an array with the exact same elements, however they are sorted by age, lowest to highest
874+
someOutput = [
875+
{
876+
name: 'Toby'
877+
age: 2
878+
}
879+
{
880+
name: 'Garth'
881+
age: 10
882+
}
883+
{
884+
name: 'Reba'
885+
age: 24
886+
}
887+
]
729888
```
730889

731890
Example: `toObject()`
732891

733892
```bicep
893+
toObject(inputArray, lambdaExpression, [lambdaExpression])
734894
// input: array
735895
// lambdaExpression: defines the key of each element for the output object
736896
// optional lambdaExpression: defines the value of each element for the output object
737-
// output: object (aka dictionary)
738-
toObject(inputArray, lambdaExpression, [lambdaExpression])
897+
// output: object
739898
740899
// example
741900
var inputArray = [
@@ -752,27 +911,65 @@ var inputArray = [
752911
output someOutput1 object = toObject(inputArray, item => item.name)
753912
// This creates a dictionary object, where the key of each element is the 'name'
754913
// Since the optional 2nd lambdaExpression was omitted, then the value becomes the original array element
755-
// So, for this example, we get a return value like this:
756-
// {
757-
// Reba: {
758-
// name: 'Reba'
759-
// age: 24
760-
// }
761-
// Garth: {
762-
// name: 'Garth'
763-
// age: 10
764-
// }
765-
// }
914+
someOutput1 = {
915+
Reba: {
916+
name: 'Reba'
917+
age: 24
918+
}
919+
Garth: {
920+
name: 'Garth'
921+
age: 10
922+
}
923+
}
766924
767925
output someOutput2 object = toObject(inputArray, item => item.name, item => item.age)
768926
// This creates a dictionary object, where the key of each element is the 'name' and the value of each one is 'age'
769927
// This example includes the optional 2nd lambaExpression, and we get a return value like this:
770-
// {
771-
// Reba: 24
772-
// Garth: 10
773-
// }
928+
someOutput2 = {
929+
Reba: 24
930+
Garth: 10
931+
}
774932
```
775933

934+
### Import / Export
935+
- First, you can specify the `@export()` decorator on any User-defined Type (`type`), User-defined Function (`func`), or Variable (`var`). This marks the item as being exportable.
936+
- Then, you can use the `import` function, in a totally different Bicep file, to import that `type`, `func`, or `var` from the first Bicep file.
937+
- Support for Compile-time Imports is generally available as of Bicep v0.25.3
938+
939+
Example `exports.bicep` file:
940+
```bicep
941+
@export()
942+
type myUserDefinedType = {
943+
something: string
944+
anotherthing: int
945+
}
946+
947+
@export()
948+
func myUserDefinedFunction(name string) string => 'Hey there ${name}'
949+
950+
@export()
951+
var myVariable = 'some constant value'
952+
// can only use constant values, or references to other variables
953+
// can not use references to resources, modules, or parameters
954+
```
955+
956+
Example `main.bicep` file:
957+
```bicep
958+
// method 1, import the given items from exports.bicep
959+
import {myUserDefinedType, myVariable} from 'exports.bicep'
960+
961+
// method 1, same as above, but define an optional alias that you can use
962+
import {myVariable as newVariableAlias} from 'exports.bicep'
963+
964+
// method 2, import everything from exports.bicep into the symbolic name allImports
965+
// then reference each item like so: allImports.myUserDefinedType, allImports.myUserDefinedFunction, allImports.myVariable
966+
import * as allImports from 'exports.bicep'
967+
```
968+
969+
Support for `.bicepparam` files
970+
- As of Bicep v0.22.6, you can import Variables in your `.bicepparam` files
971+
- As of Bicep v0.26.54, you can import User-defined Functions in your `.bicepparam` files
972+
776973
---
777974

778975
## Examples of getting info from ARM Resource Provider (WIP)

0 commit comments

Comments
 (0)