From 4f4639f711c7ec2e77f95866c3afac77e1d8d630 Mon Sep 17 00:00:00 2001 From: Alex Frankel Date: Tue, 5 Jan 2021 12:27:15 -0800 Subject: [PATCH] misc updates to readme, added PR template, added small ci/cd doc (#1245) * misc updates to readme, added PR template, cleaned up tutorial, added cicd doc * small tweaks * addressed comments * comment was in the wrong spot --- .github/PULL_REQUEST_TEMPLATE.md | 20 ++++++ CONTRIBUTING.md | 5 +- README.md | 7 ++ docs/arm2bicep.md | 8 +-- docs/cicd-with-bicep.md | 73 +++++++++++++++++++++ docs/the-any-function.md | 4 ++ docs/tutorial/05-creating-modules.md | 20 ++++-- docs/tutorial/complete-bicep-files/05.bicep | 2 + docs/tutorial/complete-bicep-files/05.json | 8 ++- 9 files changed, 135 insertions(+), 12 deletions(-) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 docs/cicd-with-bicep.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000000..0c38ee6f1a5 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,20 @@ +# Contributing a Pull Request + +If you haven't already, read the full [contribution guide](../CONTRIBUTING.md). The guide may have changed since the last time you read it, so please double-check. Once you are done and ready to submit your PR, run through the relevant checklist below. + +## Contributing to documentation + +* [ ] The contribution does not exist in any of the docs in either the root of the [docs](../docs) directory or the [specs](../docs/spec) + +## Contributing an example + +* [ ] I have checked that there is not an equivalent example already submitted +* [ ] I have resolved all warnings and errors shown by the Bicep VS Code extension +* [ ] I have checked that all tests are passing by running `dotnet test` +* [ ] I have consistent casing for all of my identifiers and am using camelCasing unless I have a justification to use another casing style + +## Contributing a feature + +* [ ] I have opened a new issue for the proposal, or commented on an existing one, and ensured that the bicep maintainers are good with the design of the feature being implemented +* [ ] I have included "Fixes #{issue_number}" in the PR description, so GitHub can link to the issue and close it when the PR is merged +* [ ] I have appropriate test coverage of my new feature diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ce628edb255..7ff3e31c983 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -65,7 +65,7 @@ If you'd like to start contributing to Bicep, you can search for issues tagged a * Ensure that an issue has been created to track the feature enhancement or bug that is being fixed. * In the PR description, make sure you've included "Fixes #{issue_number}" e.g. "Fixes #242" so that GitHub knows to link it to an issue. * To avoid multiple contributors working on the same issue, please add a comment to the issue to let us know you plan to work on it. -* If a significant amount of design is required, please include a proposal in the issue and wait for approval before working on code. If there's anything you're not sure about, please feel free to discuss this in the issue. We'd much rather all be on the same page at the start, so that there's less chance that drastic changes will be needed when your pull request is reveiwed. +* If a significant amount of design is required, please include a proposal in the issue and wait for approval before working on code. If there's anything you're not sure about, please feel free to discuss this in the issue. We'd much rather all be on the same page at the start, so that there's less chance that drastic changes will be needed when your pull request is reviewed. * We report on code coverage; please ensure any new code you add is sufficiently covered by tests. ### Example Files @@ -82,6 +82,9 @@ If you'd like to contribute example `.bicep` files that showcase abilities of th 1. All `.bicep` files have been formatted with the default Bicep auto-formatter. See [Running the tests](#running-the-tests) if you'd like to test locally before submitting a PR, and [Updating test baselines](#updating-test-baselines) for information on how to automatically update your example `.json` and `.bicep` files to match the format expected by the tests. +* If you have any test failures that are the result of compiler warnings, you may need to do either of the following: + 1. If a resource type or api version is missing, you will get a type warning. To pass the test, you will need to add that type to the list of missing types in [ExampleTests.cs](https://github.com/Azure/bicep/blob/main/src/Bicep.Core.Samples/ExamplesTests.cs#L95). + 1. If you have a false positive error or warning for a known resource type -- for example, if a property is missing an enum value -- you will need to suppress the warning using the `any()` function. You can read more about the any() function [here](./docs/the-any-function.md). * While everything will *not necessarily be applicable*, read through the Azure QuickStart Templates [Best Practices Guide](https://github.com/Azure/azure-quickstart-templates/blob/master/1-CONTRIBUTION-GUIDE/best-practices.md#best-practices) and follow it where appropriate (i.e. [parameter guidance](https://github.com/Azure/azure-quickstart-templates/blob/master/1-CONTRIBUTION-GUIDE/best-practices.md#parameters), [resource property order](https://github.com/Azure/azure-quickstart-templates/blob/master/1-CONTRIBUTION-GUIDE/best-practices.md#sort-order-of-properties), etc.) **Note:** If you have never submitted a Pull Request or used git before, reading through the [Git tutorial](https://github.com/Azure/azure-quickstart-templates/blob/master/1-CONTRIBUTION-GUIDE/git-tutorial.md) in the azure-quickstart-template repo is a good place to start. diff --git a/README.md b/README.md index 655321da74f..b1f1cb1ac9f 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,8 @@ az deployment group create -f ./main.json -g my-rg * Automatic dependency management in certain scenarios. Bicep will automatically add `dependsOn` in the compiled ARM Template if the symbolic name is used in another resource declaration. * Richer validation and intellisense than what is available in the ARM Tools VS Code extension. For example, in bicep we have intellisense on GET properties (`output sample string = resource.properties.*`) +For more detail on taking advantage of new bicep constructs that replace an equivalent from ARM Templates, you can read the [moving from ARM => Bicep](./docs/arm2bicep.md) doc. + ## Known limitations * No support for the `copy` property ([#185](https://github.com/Azure/bicep/issues/185)). @@ -104,6 +106,11 @@ Note that while we want to make it easy to transition to Bicep, we will continue * [@BicepLang](https://twitter.com/BicepLang) * [ARM Template Reference](https://docs.microsoft.com/azure/templates/) +## Community Bicep projects + +* [Bicep GitHub Action](https://github.com/marketplace/actions/bicep-build) +* [Bicep Language Service support in Neovim](https://github.com/Azure/bicep/issues/1141#issuecomment-749372637) + ## Alternatives Because we are now treating the ARM Template as an IL, we expect and encourage other implementations of IL (ARM Template) generation. We'll keep a running list of alternatives for creating ARM templates that may better fit your use case. diff --git a/docs/arm2bicep.md b/docs/arm2bicep.md index 7bfcd3e8348..d30450f19d9 100644 --- a/docs/arm2bicep.md +++ b/docs/arm2bicep.md @@ -1,6 +1,6 @@ # ARM Template syntax and the native Bicep equivalent -In Bicep, we have tried to make some common syntax in ARM templates that is quite verbose and change it to a terser equivalent. This doc is a simple table to look at all of the changes in one place. +In Bicep, we have tried to make some common syntax that in ARM templates is quite verbose and change it to a terser equivalent. This doc is a simple table to look at all of the changes in one place. Scenario | ARM Template | Bicep --- | --- | --- @@ -12,10 +12,10 @@ Get a property (`resourceProperty`) from a created resource (assumes `resource` Conditionally declare a property value | `if(parameters('isMonday'), 'valueIfTrue', 'valueIfFalse')` | `isMonday ? 'valueIfTrue' : 'valueIfFalse'` ([spec](https://github.com/Azure/bicep/blob/main/docs/spec/expressions.md#ternary-operator)) Separate a solution into multiple files | Use [linked templates](https://docs.microsoft.com/azure/azure-resource-manager/templates/linked-templates#linked-template) | Use [modules](https://github.com/Azure/bicep/blob/main/docs/spec/modules.md) Set the target scope of the deployment to a subscription | `"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#"` | `targetScope = 'subscription'` ([spec](https://github.com/Azure/bicep/blob/main/docs/spec/resource-scopes.md#declaring-the-target-scopes)) -Set a dependency between two resources | `"dependsOn": ["[resourceId('Microsoft.Storage/storageAccounts', 'parameters('storageAcountName'))]"`] | Either dependsOn not needed because of [auto-dependency management](https://github.com/Azure/bicep/blob/main/docs/spec/resources.md#implicit-dependency) or manually set dependsOn with `dependsOn: [ stg ]` ([spec](https://github.com/Azure/bicep/blob/main/docs/spec/resources.md#resource-dependencies)) +Set a dependency between two resources | `"dependsOn": ["[resourceId('Microsoft.Storage/storageAccounts', 'parameters('storageAccountName'))]"`] | Either dependsOn not needed because of [auto-dependency management](https://github.com/Azure/bicep/blob/main/docs/spec/resources.md#implicit-dependency) or manually set dependsOn with `dependsOn: [ stg ]` ([spec](https://github.com/Azure/bicep/blob/main/docs/spec/resources.md#resource-dependencies)) ## Incorporating new syntax into best practices -* Avoid the `reference()` and `resourceId()` functions like the plague. Anytime the resource you are referencing is declared in the same bicep project, you can pull the equivalent information from the resource identifier in bicep (i.e. `stg.id` or `stg.properties.primaryEndpoints.blob`). This also creates an [**implicit dependency**](https://github.com/Azure/bicep/blob/main/docs/spec/resources.md#implicit-dependency) between resources, which means you can eliminate your usage of the `dependsOn` property. All of this results in cleaner, more maintainable code. +* Avoid the `reference()` and `resourceId()` functions unless absolutely necessary. Anytime the resource you are referencing is declared in the same bicep project, you can pull the equivalent information from the resource identifier in bicep (i.e. `stg.id` or `stg.properties.primaryEndpoints.blob`). This also creates an [**implicit dependency**](https://github.com/Azure/bicep/blob/main/docs/spec/resources.md#implicit-dependency) between resources, which means you can eliminate your usage of the `dependsOn` property. All of this results in cleaner, more maintainable code. * Use consistent casing for identifiers. When in doubt, use [camel case](https://en.wikipedia.org/wiki/Camel_case) (e.g. `param myCamelCasedParameter string`) -* If you are going to add a `description` to a parameter, ensure the parameter is in fact descriptive. If you have a `location` parameter, having a description of "the resource's location" is not particularly helpful and results in your code being noisier. Sometimes a `//` comment is more appropriate. +* If you are going to add a `description` to a parameter, ensure the parameter is in fact descriptive. For example, if you have a `location` parameter, having a description of "the resource's location" is not particularly helpful and results in noisy code. Sometimes a `//` comment is more appropriate. diff --git a/docs/cicd-with-bicep.md b/docs/cicd-with-bicep.md new file mode 100644 index 00000000000..af6d7fa8153 --- /dev/null +++ b/docs/cicd-with-bicep.md @@ -0,0 +1,73 @@ +# Adding bicep to a CI/CD pipeline + +As your bicep practice matures, you will want to check-in your bicep code into source control and kick off a pipeline or workflow, which would do the following: + +1. Build your bicep file into an ARM Template +1. Deploy the generated ARM template + +In order to do this, we need to make sure the bicep CLI is installed on the build agent. For now, bicep is not preinstalled on any build agents or tasks provided by Microsoft, but installing it manually as part of the pipeline is straightforward. + +The following example is designed to be run in GitHub actions workflow and uses Azure CLI, but could be easily adapted to run in a Azure DevOps Pipeline. It assumes the following prerequisite: + +* The bicep file you want to transpile and deploy is called `main.bicep` and exists in the root of the repo +* You are deploying the transpiled ARM Template to a resource group. Deploying to another scope like a subscription requires a different CLI command. + +```yaml + +name: bicep build and deploy + +on: push + +jobs: + bicep-build-and-deploy: + name: bicep build and deploy + runs-on: ubuntu-latest + + steps: + # Checks out a copy of your repository on the ubuntu-latest machine + - name: Checkout code + uses: actions/checkout@v2 + + # Install the latest release of the bicep CLI + - name: Install bicep CLI + run: | + curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 + chmod +x ./bicep + sudo mv ./bicep /usr/local/bin/bicep + bicep --help + + # Transpile bicep file into ARM template + - name: Build ARM Template from bicep file + run: | + bicep build ./main.bicep + + # Stop here if you only want to do "CI" which just generates the + # build artifact (ARM Template JSON) + + # Login to Azure + - name: Azure Login + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + # Emit template what-if to show what template will do + - name: Run what-if + uses: azure/CLI@v1 + with: + inlineScript: | + az account show + az deployment group what-if -f ./main.json -p ./parameters.json -g my-rg + + # You may want a human approval in between the what-if step + # and the deploy step to evaluate output before deployment + + # Deploy template + - name: Deploy template + uses: azure/CLI@v1 + with: + inlineScript: | + az account show + az deployment group create -f ./main.json -g my-rg +``` + +Instead of installing the bicep CLI manually, you may instead want to use the [community-maintained github action](https://github.com/marketplace/actions/bicep-build) from [@justinyoo](https://github.com/justinyoo) that can run `bicep build` on your behalf. diff --git a/docs/the-any-function.md b/docs/the-any-function.md index 52ebb80b3f4..0d9631ce89b 100644 --- a/docs/the-any-function.md +++ b/docs/the-any-function.md @@ -68,3 +68,7 @@ resource wpAci 'microsoft.containerInstance/containerGroups@2019-12-01' = { You can see in the live code in [the playground](https://aka.ms/bicepdemo#eJyNVFtv2jAUfs+v8JvhgSTQbV0jbRodW1epa7MGdQ/TVBnHgKXENr5A0cR/n53gEIJQmzzEOT7fxUfHRyCJSqA0l2hBxhhzw/Q9KokNScoW4BMwjK4MyarfniSKG4nJjeRG9PohzfuBqCmoJsfAU9Jgn1tus1WRIqU2XOYe8C8AQBFsJEmAloYEO59ecIw05exA3bXhM4Ig8FtgI8aYAlhSLLnicx1izjSijMhbpjRimERNpOJRX0bx8GowHA3iIbQizhCzrhMAnU9hmdWggdA9CbRZXj5pVjYoJBdEakpUUlEB0GBt5E8VAfsd93SlYLNzylQ/tLTlbUOSd+HVAAmElwS28gSXuiXZFW5ENMe8sHzTryns7lqKBHyMj8K71t/f1pqwNZWclYTpJyQpmhXkVfn96X8/PE7Sx29Z9jy5fv7xkE27RtaoMC5xOLoMY/sOk4uL+AM86+ttSuk4y1ygq1b341Otedy1UQTwErEFyYFeUgXmkpcAVvZs83wGsIU9b69dtjUvTEl+usvyarlKl5UivbQnidZIRpvNJlrqsuieoNtVc1q80Y6/SJ2mcxt2Hih9ErcNLkwCENv2YBy+h/2uZ1Jyub1lN9dN0mUnqe3lsPar+lt7pGKc51XPNy5O2rxt73x7n7S2l/PF0FvhSpiaWUGxR+ZMuYl2h2bEcvrhFxzwXE1r3B1l5sXBdm6icaOF0RXg+6/J/WGkVeMqPFz1sDlhOF/l7D8GbIVb), the warnings go away. `any()` works on any assigned value in bicep. You can see a more complex use of `any()` in the `nested-vms-in-virtual-network` example on [line 31](https://github.com/Azure/bicep/blob/main/docs/examples/301/nested-vms-in-virtual-network/nic.bicep#L31) of `nic.bicep` in which the use of `any()` wraps the entire ternary expression as an argument. + +For more complex uses of the `any()` function, you can look at some of the below examples: +* [Child resources that require a specific names](https://github.com/Azure/bicep/blob/main/docs/examples/201/api-management-create-all-resources/main.bicep#L246) +* [A resource property is not defined in the resource's type, even though it exists](https://github.com/Azure/bicep/blob/main/docs/examples/201/log-analytics-with-solutions-and-diagnostics/main.bicep#L26) diff --git a/docs/tutorial/05-creating-modules.md b/docs/tutorial/05-creating-modules.md index dd01c6c9c66..0e887bd021e 100644 --- a/docs/tutorial/05-creating-modules.md +++ b/docs/tutorial/05-creating-modules.md @@ -169,20 +169,28 @@ Since the `targetScope` has been changed, notice that the `$schema` property in Modules are a powerful way to separate your bicep files into logical units and abstract away complex resource declarations. ## Using if condition with bicep Modules -Modules also support the if condition (introduced in v0.2.212). The linked ARM template produced by `bicep build` will insert a condition at the deployment level for everything in the module. To take advantage of this the module declaration needs to follow the if condition syntax: -```` + +Modules also support the `if` keyword to conditionally deploy the module. Let's add a new `param` called `deployStorage` and use it conditionally deploy the storage account module: + +``` +param deployStorage bool = true + module stg './storage.bicep' = if (deployStorage) { name: 'storageDeploy' } -```` -In this example if the parameter of `deployStorage` is set to `false` then everything in the module will be skipped at deployment. If `deployStorage` is set to `true` the module will be deployed. The ARM template created by running `bicep build` will look like: -```` +``` + +In this example if the parameter of `deployStorage` is set to `false` then everything in the module will be skipped at deployment. If `deployStorage` is set to `true` then the module will be deployed. + +The linked ARM template produced by `bicep build` will add the `condition` property to the entire nested deployment resource, which is what represents the compiled module. It will look like the following: + +``` { "condition": "[parameters('deployStorage')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2019-10-01", ..... -```` +``` Thus combining modules with the usage of the if() condition allows for customizing deployed components based on criteria and/or parameters. diff --git a/docs/tutorial/complete-bicep-files/05.bicep b/docs/tutorial/complete-bicep-files/05.bicep index 643fcc4e856..8b8ad1e4521 100644 --- a/docs/tutorial/complete-bicep-files/05.bicep +++ b/docs/tutorial/complete-bicep-files/05.bicep @@ -1,5 +1,7 @@ targetScope = 'subscription' +param deployStorage bool = true + module stg './storage.bicep' = { name: 'storageDeploy' scope: resourceGroup('brittle-hollow') // this will target another resource group in the same subscription diff --git a/docs/tutorial/complete-bicep-files/05.json b/docs/tutorial/complete-bicep-files/05.json index 2e90ea34e12..389b771c9fe 100644 --- a/docs/tutorial/complete-bicep-files/05.json +++ b/docs/tutorial/complete-bicep-files/05.json @@ -1,6 +1,12 @@ { "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", "contentVersion": "1.0.0.0", + "parameters": { + "deployStorage": { + "type": "bool", + "defaultValue": true + } + }, "functions": [], "variables": { "objectId": "cf024e4c-f790-45eb-a992-5218c39bde1a", @@ -93,7 +99,7 @@ "outputs": { "storageName": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', 'stg'), '2019-10-01').outputs.computedStorageName.value]" + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, 'brittle-hollow'), 'Microsoft.Resources/deployments', 'storageDeploy'), '2019-10-01').outputs.computedStorageName.value]" } } } \ No newline at end of file