├── .artifactignore ├── .azuredevops └── azure-pipelines-ci.yml ├── .devcontainer └── devcontainer.json ├── .editorconfig ├── .gitattributes ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml └── workflows │ ├── codeql.yml │ ├── dependabot_hack.yml │ ├── github-action-ci.yml │ └── sonarqube.yml ├── .gitignore ├── .markdownlint.yaml ├── .pre-commit-config.yaml ├── .pre-commit-hooks.yaml ├── .vscode ├── extensions.json └── settings.json ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── az_bicep_build.ps1 ├── az_bicep_format.ps1 ├── check-azure-bicep.code-workspace ├── checkazurebiceppython └── __init__.py ├── requirements.txt ├── setup.py ├── test.bicep └── tests ├── az_bicep_format_python_test.py ├── az_bicep_format_python_test_integration.py └── testfail.bicep /.artifactignore: -------------------------------------------------------------------------------- 1 | .git 2 | .vscode 3 | .azuredevops 4 | .github 5 | -------------------------------------------------------------------------------- /.azuredevops/azure-pipelines-ci.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | system.debug: true 3 | 4 | trigger: 5 | - master 6 | - develop 7 | - release/* 8 | - feature/* 9 | - hotfix/* 10 | 11 | pool: 12 | vmImage: 'ubuntu-latest' 13 | 14 | jobs: 15 | - job: AgentJobGitVersion 16 | displayName: Agent job - GitVersion 17 | steps: 18 | - task: gittools.gittools.setup-gitversion-task.gitversion/setup@0 19 | displayName: gitversion/setup 20 | inputs: 21 | versionSpec: 5.x 22 | 23 | - task: gittools.gittools.execute-gitversion-task.gitversion/execute@0 24 | displayName: gitversion/execute 25 | 26 | - job: AgentJobMain 27 | displayName: Agent job - Main 28 | strategy: 29 | maxParallel: 99 30 | matrix: 31 | linux: 32 | imageName: 'ubuntu-latest' 33 | mac: 34 | imageName: 'macOS-latest' 35 | windows: 36 | imageName: 'windows-latest' 37 | pool: 38 | vmImage: $(imageName) 39 | 40 | steps: 41 | - task: UsePythonVersion@0 42 | inputs: 43 | versionSpec: '3.10.x' 44 | addToPath: true 45 | architecture: 'x64' 46 | 47 | - bash: | 48 | if [ -f .pre-commit-config.yaml ]; then 49 | echo "##vso[task.setVariable variable=FILEEXISTS_PRECOMMIT]true" 50 | fi 51 | displayName: Check if .pre-commit-config.yaml exist 52 | - script: | 53 | az bicep install 54 | condition: eq(variables.imageName, 'macOS-latest') 55 | retryCountOnTaskFailure: 5 56 | displayName: Run az bicep install on macOS-latest on ADO 57 | - script: | 58 | pip install pre-commit 59 | pre-commit --version 60 | pre-commit run --all-files 61 | condition: eq(variables.FILEEXISTS_PRECOMMIT, 'true') 62 | displayName: Execture pre-commit 63 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Development Environment", 3 | "extensions": [ 4 | "msazurermtools.azurerm-vscode-tools", 5 | "ms-azuretools.vscode-bicep", 6 | "ms-dotnettools.csharp", 7 | "ms-azuretools.vscode-docker", 8 | "editorconfig.editorconfig", 9 | "github.vscode-pull-request-github" 10 | ], 11 | "features": { 12 | "github-cli": "latest", 13 | "azure-cli": "latest", 14 | "node": { 15 | "version": "lts", 16 | "nodeGypDependencies": true 17 | }, 18 | "dotnet": { 19 | "version": "6.0" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | end_of_line = lf 8 | 9 | [*.{cs,csx,vb,vbx}] 10 | indent_size = 4 11 | 12 | [*.xml] 13 | indent_size = 2 14 | 15 | [*.{yml,yaml}] 16 | indent_size = 2 17 | 18 | [*.sln] 19 | indent_style = tab 20 | 21 | ############################### 22 | # .NET Coding Conventions # 23 | ############################### 24 | [*.{cs,vb}] 25 | # Organize usings 26 | dotnet_sort_system_directives_first = true 27 | # this. preferences 28 | dotnet_style_qualification_for_field = false:silent 29 | dotnet_style_qualification_for_property = false:silent 30 | dotnet_style_qualification_for_method = false:silent 31 | dotnet_style_qualification_for_event = false:silent 32 | # Language keywords vs BCL types preferences 33 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent 34 | dotnet_style_predefined_type_for_member_access = true:silent 35 | # Parentheses preferences 36 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent 37 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent 38 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent 39 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent 40 | # Modifier preferences 41 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent 42 | dotnet_style_readonly_field = true:suggestion 43 | # Expression-level preferences 44 | dotnet_style_object_initializer = true:suggestion 45 | dotnet_style_collection_initializer = true:suggestion 46 | dotnet_style_explicit_tuple_names = true:suggestion 47 | dotnet_style_null_propagation = true:suggestion 48 | dotnet_style_coalesce_expression = true:suggestion 49 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent 50 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 51 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 52 | dotnet_style_prefer_auto_properties = true:silent 53 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 54 | dotnet_style_prefer_conditional_expression_over_return = true:silent 55 | ############################### 56 | # Naming Conventions # 57 | ############################### 58 | # Style Definitions 59 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case 60 | # Use PascalCase for constant fields 61 | dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion 62 | dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields 63 | dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style 64 | dotnet_naming_symbols.constant_fields.applicable_kinds = field 65 | dotnet_naming_symbols.constant_fields.applicable_accessibilities = * 66 | dotnet_naming_symbols.constant_fields.required_modifiers = const 67 | ############################### 68 | # C# Coding Conventions # 69 | ############################### 70 | [*.cs] 71 | # var preferences 72 | csharp_style_var_for_built_in_types = true:silent 73 | csharp_style_var_when_type_is_apparent = true:silent 74 | csharp_style_var_elsewhere = true:silent 75 | # Expression-bodied members 76 | csharp_style_expression_bodied_methods = false:silent 77 | csharp_style_expression_bodied_constructors = false:silent 78 | csharp_style_expression_bodied_operators = false:silent 79 | csharp_style_expression_bodied_properties = true:silent 80 | csharp_style_expression_bodied_indexers = true:silent 81 | csharp_style_expression_bodied_accessors = true:silent 82 | # Pattern matching preferences 83 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 84 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 85 | # Null-checking preferences 86 | csharp_style_throw_expression = true:suggestion 87 | csharp_style_conditional_delegate_call = true:suggestion 88 | # Modifier preferences 89 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion 90 | # Expression-level preferences 91 | csharp_prefer_braces = true:silent 92 | csharp_style_deconstructed_variable_declaration = true:suggestion 93 | csharp_prefer_simple_default_expression = true:suggestion 94 | csharp_style_pattern_local_over_anonymous_function = true:suggestion 95 | csharp_style_inlined_variable_declaration = true:suggestion 96 | ############################### 97 | # C# Formatting Rules # 98 | ############################### 99 | # New line preferences 100 | csharp_new_line_before_open_brace = all 101 | csharp_new_line_before_else = true 102 | csharp_new_line_before_catch = true 103 | csharp_new_line_before_finally = true 104 | csharp_new_line_before_members_in_object_initializers = true 105 | csharp_new_line_before_members_in_anonymous_types = true 106 | csharp_new_line_between_query_expression_clauses = true 107 | # Indentation preferences 108 | csharp_indent_case_contents = true 109 | csharp_indent_switch_labels = true 110 | csharp_indent_labels = flush_left 111 | # Space preferences 112 | csharp_space_after_cast = false 113 | csharp_space_after_keywords_in_control_flow_statements = true 114 | csharp_space_between_method_call_parameter_list_parentheses = false 115 | csharp_space_between_method_declaration_parameter_list_parentheses = false 116 | csharp_space_between_parentheses = false 117 | csharp_space_before_colon_in_inheritance_clause = true 118 | csharp_space_after_colon_in_inheritance_clause = true 119 | csharp_space_around_binary_operators = before_and_after 120 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 121 | csharp_space_between_method_call_name_and_opening_parenthesis = false 122 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 123 | # Wrapping preferences 124 | csharp_preserve_single_line_statements = true 125 | csharp_preserve_single_line_blocks = true 126 | ############################### 127 | # VB Coding Conventions # 128 | ############################### 129 | [*.vb] 130 | # Modifier preferences 131 | visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion 132 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @JanuszNowak 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '39 3 * * 3' 22 | workflow_dispatch: 23 | 24 | jobs: 25 | analyze: 26 | name: Analyze 27 | runs-on: ubuntu-latest 28 | permissions: 29 | actions: read 30 | contents: read 31 | security-events: write 32 | 33 | strategy: 34 | fail-fast: false 35 | matrix: 36 | language: [ 'python' ] 37 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 38 | # Use only 'java' to analyze code written in Java, Kotlin or both 39 | # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both 40 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 41 | 42 | steps: 43 | - name: Checkout repository 44 | uses: actions/checkout@v4 45 | 46 | # Initializes the CodeQL tools for scanning. 47 | - name: Initialize CodeQL 48 | uses: github/codeql-action/init@v3 49 | with: 50 | languages: ${{ matrix.language }} 51 | # If you wish to specify custom queries, you can do so here or in a config file. 52 | # By default, queries listed here will override any specified in a config file. 53 | # Prefix the list here with "+" to use these queries and those in the config file. 54 | 55 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 56 | # queries: security-extended,security-and-quality 57 | 58 | 59 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 60 | # If this step fails, then you should remove it and run the build manually (see below) 61 | - name: Autobuild 62 | uses: github/codeql-action/autobuild@v3 63 | 64 | # ℹ️ Command-line programs to run using the OS shell. 65 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 66 | 67 | # If the Autobuild fails above, remove it and uncomment the following three lines. 68 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 69 | 70 | # - run: | 71 | # echo "Run, Build Application using script" 72 | # ./location_of_script_within_repo/buildscript.sh 73 | 74 | - name: Perform CodeQL Analysis 75 | uses: github/codeql-action/analyze@v3 76 | with: 77 | category: "/language:${{matrix.language}}" 78 | -------------------------------------------------------------------------------- /.github/workflows/dependabot_hack.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # See ../DEPENDENCIES.md#workaround-for-other-dependencies 3 | name: Dependabot hack 4 | on: # yamllint disable-line rule:truthy 5 | push: 6 | branches: 7 | - never-trigger-this-dependabot-hack-workflow 8 | workflow_dispatch: 9 | 10 | jobs: 11 | dependabot_hack: 12 | name: Ensure dependabot version checks 13 | runs-on: "ubuntu-latest" 14 | steps: 15 | # Dockerfile: 16 | - uses: azure/azure-cli@azure-cli-2.67.0 17 | - uses: azure/bicep@v0.32.4 18 | - uses: pre-commit/pre-commit@v4.0.1 19 | 20 | -------------------------------------------------------------------------------- /.github/workflows/github-action-ci.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the workflow will run 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the "master" branch 8 | push: 9 | branches: ["master"] 10 | pull_request: 11 | branches: ["master"] 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | workflow_dispatch: 15 | 16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 17 | jobs: 18 | # This workflow contains a single job called "build" 19 | GitVersion: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Fetch all history for all tags and branches 24 | run: git fetch --prune --unshallow 25 | - name: Install GitVersion 26 | uses: gittools/actions/gitversion/setup@v3.1.1 27 | with: 28 | versionSpec: "5.x" 29 | - name: Determine Version 30 | uses: gittools/actions/gitversion/execute@v3.1.1 31 | 32 | build: 33 | runs-on: ${{ matrix.os }} 34 | # The type of runner that the job will run on 35 | strategy: 36 | fail-fast: false 37 | max-parallel: 99 38 | matrix: 39 | os: [ubuntu-latest, windows-latest, macos-latest] 40 | 41 | # Steps represent a sequence of tasks that will be executed as part of the job 42 | steps: 43 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 44 | - uses: actions/checkout@v4 45 | - name: Setup Python 46 | uses: actions/setup-python@v5.3.0 47 | with: 48 | # Version range or exact version of Python to use, using SemVer's version range syntax. Reads from .python-version if unset. 49 | python-version: '3.10' 50 | - name: Run a multi-line script 51 | run: | 52 | pip install pre-commit 53 | pre-commit --version 54 | pre-commit run --all-files 55 | -------------------------------------------------------------------------------- /.github/workflows/sonarqube.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | # This workflow helps you trigger a SonarQube analysis of your code and populates 7 | # GitHub Code Scanning alerts with the vulnerabilities found. 8 | # (this feature is available starting from SonarQube 9.7, Developer Edition and above) 9 | 10 | # 1. Make sure you add a valid GitHub configuration to your SonarQube (Administration > DevOps platforms > GitHub) 11 | 12 | # 2. Import your project on SonarQube 13 | # * Add your repository as a new project by clicking "Create project" from your homepage. 14 | # 15 | # 3. Select GitHub Actions as your CI and follow the tutorial 16 | # * a. Generate a new token and add it to your GitHub repository's secrets using the name SONAR_TOKEN 17 | # (On SonarQube, click on your avatar on top-right > My account > Security or ask your administrator) 18 | # 19 | # * b. Copy/paste your SonarQube host URL to your GitHub repository's secrets using the name SONAR_HOST_URL 20 | # 21 | # * c. Copy/paste the project Key into the args parameter below 22 | # (You'll find this information in SonarQube by following the tutorial or by clicking on Project Information at the top-right of your project's homepage) 23 | 24 | # Feel free to take a look at our documentation (https://docs.sonarqube.org/latest/analysis/github-integration/) 25 | # or reach out to our community forum if you need some help (https://community.sonarsource.com/c/sq/10) 26 | 27 | name: SonarQube analysis 28 | 29 | on: 30 | push: 31 | branches: [ "master" ] 32 | pull_request: 33 | branches: [ "master" ] 34 | workflow_dispatch: 35 | 36 | permissions: 37 | pull-requests: read # allows SonarQube to decorate PRs with analysis results 38 | 39 | jobs: 40 | Analysis: 41 | runs-on: ubuntu-latest 42 | 43 | steps: 44 | - name: Analyze with SonarQube 45 | 46 | # You can pin the exact commit or the version. 47 | # uses: SonarSource/sonarqube-scan-action@v1.1.0 48 | uses: SonarSource/sonarqube-scan-action@bfd4e558cda28cda6b5defafb9232d191be8c203 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information 51 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # Generate a token on SonarQube, add it to the secrets of this repo with the name SONAR_TOKEN (Settings > Secrets > Actions > add new repository secret) 52 | SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} # add the URL of your instance to the secrets of this repo with the name SONAR_HOST_URL (Settings > Secrets > Actions > add new repository secret) 53 | with: 54 | # Additional arguments for the sonarcloud scanner 55 | args: 56 | # Unique key of your project. You can find it in SonarQube > [my project] > Project Information (top-right menu) 57 | # mandatory 58 | -Dsonar.projectKey= 59 | # Comma-separated paths to directories containing main source files. 60 | #-Dsonar.sources= # optional, default is project base directory 61 | # When you need the analysis to take place in a directory other than the one from which it was launched 62 | #-Dsonar.projectBaseDir= # optional, default is . 63 | # Comma-separated paths to directories containing test source files. 64 | #-Dsonar.tests= # optional. For more info about Code Coverage, please refer to https://docs.sonarcloud.io/enriching/test-coverage/overview/ 65 | # Adds more detail to both client and server-side analysis logs, activating DEBUG mode for the scanner, and adding client-side environment variables and system properties to the server-side log of analysis report processing. 66 | #-Dsonar.verbose= # optional, default is false 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | # Example markdownlint YAML configuration with all properties set to their default value 2 | 3 | # Default state for all rules 4 | default: true 5 | 6 | # Path to configuration file to extend 7 | extends: 8 | 9 | # MD001/heading-increment/header-increment - Heading levels should only increment by one level at a time 10 | MD001: true 11 | 12 | # MD002/first-heading-h1/first-header-h1 - First heading should be a top-level heading 13 | MD002: 14 | # Heading level 15 | level: 1 16 | 17 | # MD003/heading-style/header-style - Heading style 18 | MD003: 19 | # Heading style 20 | style: consistent 21 | 22 | # MD004/ul-style - Unordered list style 23 | MD004: 24 | # List style 25 | style: consistent 26 | 27 | # MD005/list-indent - Inconsistent indentation for list items at the same level 28 | MD005: true 29 | 30 | # MD006/ul-start-left - Consider starting bulleted lists at the beginning of the line 31 | MD006: true 32 | 33 | # MD007/ul-indent - Unordered list indentation 34 | MD007: 35 | # Spaces for indent 36 | indent: 37 | 2 38 | # Whether to indent the first level of the list 39 | start_indented: 40 | false 41 | # Spaces for first level indent (when start_indented is set) 42 | start_indent: 2 43 | 44 | # MD009/no-trailing-spaces - Trailing spaces 45 | MD009: 46 | # Spaces for line break 47 | br_spaces: 48 | 2 49 | # Allow spaces for empty lines in list items 50 | list_item_empty_lines: 51 | false 52 | # Include unnecessary breaks 53 | strict: false 54 | 55 | # MD010/no-hard-tabs - Hard tabs 56 | MD010: 57 | # Include code blocks 58 | code_blocks: 59 | true 60 | # Number of spaces for each hard tab 61 | spaces_per_tab: 1 62 | 63 | # MD011/no-reversed-links - Reversed link syntax 64 | MD011: true 65 | 66 | # MD012/no-multiple-blanks - Multiple consecutive blank lines 67 | MD012: 68 | # Consecutive blank lines 69 | maximum: 1 70 | 71 | # MD013/line-length - Line length 72 | MD013: 73 | # Number of characters 74 | line_length: 75 | 999 76 | # Number of characters for headings 77 | heading_line_length: 78 | 180 79 | # Number of characters for code blocks 80 | code_block_line_length: 81 | 180 82 | # Include code blocks 83 | code_blocks: 84 | true 85 | # Include tables 86 | tables: 87 | true 88 | # Include headings 89 | headings: 90 | true 91 | # Include headings 92 | headers: 93 | true 94 | # Strict length checking 95 | strict: 96 | false 97 | # Stern length checking 98 | stern: false 99 | 100 | # MD014/commands-show-output - Dollar signs used before commands without showing output 101 | MD014: true 102 | 103 | # MD018/no-missing-space-atx - No space after hash on atx style heading 104 | MD018: true 105 | 106 | # MD019/no-multiple-space-atx - Multiple spaces after hash on atx style heading 107 | MD019: true 108 | 109 | # MD020/no-missing-space-closed-atx - No space inside hashes on closed atx style heading 110 | MD020: true 111 | 112 | # MD021/no-multiple-space-closed-atx - Multiple spaces inside hashes on closed atx style heading 113 | MD021: true 114 | 115 | # MD022/blanks-around-headings/blanks-around-headers - Headings should be surrounded by blank lines 116 | MD022: 117 | # Blank lines above heading 118 | lines_above: 119 | 1 120 | # Blank lines below heading 121 | lines_below: 1 122 | 123 | # MD023/heading-start-left/header-start-left - Headings must start at the beginning of the line 124 | MD023: true 125 | 126 | # MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content 127 | MD024: 128 | # Only check sibling headings 129 | allow_different_nesting: 130 | false 131 | # Only check sibling headings 132 | siblings_only: false 133 | 134 | # MD025/single-title/single-h1 - Multiple top-level headings in the same document 135 | MD025: 136 | # Heading level 137 | level: 138 | 1 139 | # RegExp for matching title in front matter 140 | front_matter_title: ^\s*title\s*[:=] 141 | 142 | # MD026/no-trailing-punctuation - Trailing punctuation in heading 143 | MD026: 144 | # Punctuation characters 145 | punctuation: .,;:!。,;:! 146 | 147 | # MD027/no-multiple-space-blockquote - Multiple spaces after blockquote symbol 148 | MD027: true 149 | 150 | # MD028/no-blanks-blockquote - Blank line inside blockquote 151 | MD028: true 152 | 153 | # MD029/ol-prefix - Ordered list item prefix 154 | MD029: 155 | # List style 156 | style: one_or_ordered 157 | 158 | # MD030/list-marker-space - Spaces after list markers 159 | MD030: 160 | # Spaces for single-line unordered list items 161 | ul_single: 162 | 1 163 | # Spaces for single-line ordered list items 164 | ol_single: 165 | 1 166 | # Spaces for multi-line unordered list items 167 | ul_multi: 168 | 1 169 | # Spaces for multi-line ordered list items 170 | ol_multi: 1 171 | 172 | # MD031/blanks-around-fences - Fenced code blocks should be surrounded by blank lines 173 | MD031: 174 | # Include list items 175 | list_items: true 176 | 177 | # MD032/blanks-around-lists - Lists should be surrounded by blank lines 178 | MD032: true 179 | 180 | # MD033/no-inline-html - Inline HTML 181 | MD033: 182 | # Allowed elements 183 | allowed_elements: [] 184 | 185 | # MD034/no-bare-urls - Bare URL used 186 | MD034: true 187 | 188 | # MD035/hr-style - Horizontal rule style 189 | MD035: 190 | # Horizontal rule style 191 | style: consistent 192 | 193 | # MD036/no-emphasis-as-heading/no-emphasis-as-header - Emphasis used instead of a heading 194 | MD036: 195 | # Punctuation characters 196 | punctuation: .,;:!?。,;:!? 197 | 198 | # MD037/no-space-in-emphasis - Spaces inside emphasis markers 199 | MD037: true 200 | 201 | # MD038/no-space-in-code - Spaces inside code span elements 202 | MD038: true 203 | 204 | # MD039/no-space-in-links - Spaces inside link text 205 | MD039: true 206 | 207 | # MD040/fenced-code-language - Fenced code blocks should have a language specified 208 | MD040: true 209 | 210 | # MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading 211 | MD041: false 212 | # # Heading level 213 | # level: 214 | # 1 215 | # # RegExp for matching title in front matter 216 | # front_matter_title: ^\s*title\s*[:=] 217 | 218 | # MD042/no-empty-links - No empty links 219 | MD042: true 220 | 221 | # MD043/required-headings/required-headers - Required heading structure 222 | # MD043: 223 | # # List of headings 224 | # headings: [] 225 | # # List of headings 226 | # headers: [] 227 | 228 | # MD044/proper-names - Proper names should have the correct capitalization 229 | MD044: 230 | # List of proper names 231 | names: 232 | [] 233 | # Include code blocks 234 | code_blocks: true 235 | 236 | # MD045/no-alt-text - Images should have alternate text (alt text) 237 | MD045: true 238 | 239 | # MD046/code-block-style - Code block style 240 | MD046: 241 | # Block style 242 | style: consistent 243 | 244 | # MD047/single-trailing-newline - Files should end with a single newline character 245 | MD047: true 246 | 247 | # MD048/code-fence-style - Code fence style 248 | MD048: 249 | # Code fence style 250 | style: consistent 251 | 252 | # MD049/emphasis-style - Emphasis style should be consistent 253 | MD049: 254 | # Emphasis style should be consistent 255 | style: consistent 256 | 257 | # MD050/strong-style - Strong style should be consistent 258 | MD050: 259 | # Strong style should be consistent 260 | style: consistent 261 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.5.0 4 | hooks: 5 | - id: check-json 6 | - id: check-yaml 7 | - id: check-xml 8 | - id: check-executables-have-shebangs 9 | # - repo: https://github.com/Azure4DevOps/check-azure-bicep 10 | # rev: v0.5.3 11 | # hooks: 12 | # - id: check-azure-bicep 13 | # - id: check-azure-bicep-python 14 | # - id: check-azure-bicep-format 15 | # - id: check-azure-bicep-format-python 16 | 17 | # - repo: local 18 | # hooks: 19 | # - id: check-azure-bicep 20 | # name: check-azure-bicep 21 | # language: system 22 | # #entry: powershell -File ./src/az_bicep_build.ps1 23 | # entry: pwsh -File ./src/az_bicep_build.ps1 24 | # pass_filenames: true 25 | # files: .*.bicep$ 26 | 27 | 28 | - repo: local 29 | hooks: 30 | - id: check-azure-bicep 31 | name: check-azure-bicep 32 | language: system 33 | entry: pwsh -File ./az_bicep_build.ps1 34 | pass_filenames: true 35 | files: .*\.bicep$ 36 | - id: check-azure-bicep-format 37 | name: check-azure-bicep-format 38 | language: system 39 | entry: pwsh -File ./az_bicep_format.ps1 40 | pass_filenames: true 41 | files: .*\.bicep$ -------------------------------------------------------------------------------- /.pre-commit-hooks.yaml: -------------------------------------------------------------------------------- 1 | - id: check-azure-bicep 2 | name: az bicep build 3 | language: script 4 | require_serial: true 5 | entry: az_bicep_build.ps1 6 | files: .*\.bicep$ 7 | 8 | - id: check-azure-bicep-python 9 | name: az bicep build (python) 10 | language: python 11 | pass_filenames: false 12 | require_serial: true 13 | entry: entry_az_bicep_build 14 | files: .*\.bicep$ 15 | additional_dependencies: ['azure-cli'] 16 | 17 | - id: check-azure-bicep-format 18 | name: az bicep format 19 | language: script 20 | require_serial: true 21 | entry: az_bicep_format.ps1 22 | files: .*\.bicep$ 23 | 24 | - id: check-azure-bicep-format-python 25 | name: az bicep format (python) 26 | language: python 27 | pass_filenames: false 28 | require_serial: true 29 | entry: entry_az_bicep_format 30 | files: .*\.bicep$ 31 | additional_dependencies: ['azure-cli'] 32 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "EditorConfig.EditorConfig", 4 | "esbenp.prettier-vscode", 5 | "esbenp.prettier-vscode", 6 | "ms-vscode.PowerShell", 7 | "ms-python.python", 8 | "VisualStudioExptTeam.vscodeintellicode", 9 | "ms-azuretools.vscode-docker", 10 | "ms-vscode.vscode-typescript-tslint-plugin", 11 | "msazurermtools.azurerm-vscode-tools" 12 | ], 13 | "unwantedRecommendations": [] 14 | } 15 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnPaste": true, 3 | "editor.formatOnSave": true, 4 | "eslint.format.enable": true, 5 | "eslint.lintTask.enable": true, 6 | "[typescript]": { 7 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 8 | }, 9 | "yaml.schemas": { 10 | "https://json.schemastore.org/github-workflow.json": "/.github/workflows/*.yml" 11 | }, 12 | "cSpell.words": ["pwsh"] 13 | } 14 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | . 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Janusz Nowak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://dev.azure.com/Azure4DevOps/Azure4DevOps/_apis/build/status/Azure4DevOps.check-azure-bicep-ci?branchName=master)](https://dev.azure.com/Azure4DevOps/Azure4DevOps/_build/latest?definitionId=2&branchName=master) 2 | [![CI](https://github.com/Azure4DevOps/check-azure-bicep/actions/workflows/github-action-ci.yml/badge.svg)](https://github.com/Azure4DevOps/check-azure-bicep/actions/workflows/github-action-ci.yml) 3 | ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/Azure4DevOps/check-azure-bicep) 4 | ![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/Azure4DevOps/check-azure-bicep?include_prereleases) 5 | [![pre-commit][pre-commit-image]][pre-commit-link] 6 | 7 | [pre-commit-image]: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&style=flat-square 8 | [pre-commit-link]: https://github.com/pre-commit/pre-commit 9 | 10 | # check-azure-bicep 11 | 12 | [pre-commit](https://pre-commit.com/) hooks for [Azure Bicep](https://github.com/Azure/bicep) validation, 13 | with built-in support for GitHub Workflows, Azure Pipelines, and more! Enabling [shift left](https://devopedia.org/shift-left) approach for [Azure Bicep](https://github.com/Azure/bicep) infrastructure as code. 14 | 15 | ## About 16 | 17 | This repository provide one hook to use with [pre-commit](https://pre-commit.com/) that validate bicep files: it will call `az bicep build`. 18 | 19 | It requires the `az bicep` toolchain installed, and uses [`az bicep`](https://github.com/Azure/bicep) under the hood. 20 | 21 | ## Demo 22 | 23 | Example usage of `pre-commit run --all-files` and 24 | `git commit` after hook innstall in git repository `pre-commit install` 25 | 26 | ![alt text](https://raw.githubusercontent.com/Azure4DevOps/check-azure-bicep.example/master/example.gif) 27 | 28 | ### Azure Bicep Install 29 | 30 | To install `az bicep` use [install](https://docs.microsoft.com/pl-pl/azure/azure-resource-manager/bicep/install) or [install](https://github.com/Azure/bicep) or `az bicep install` for Azure cli. 31 | 32 | ### pre-commit Install 33 | 34 | Before you can run hooks, you need to have the pre-commit package manager installed. Using pip: 35 | 36 | ```pip 37 | # install using pip 38 | pip install pre-commit 39 | 40 | # check if working - expected print with version like `pre-commit 3.2.2` 41 | pre-commit --version 42 | 43 | # setup the git repo for hooks 44 | pre-commit install 45 | 46 | # periodically run updates to your pre-commit config to make sure you always have the latest version of the hooks 47 | pre-commit autoupdate 48 | ``` 49 | 50 | ## Example usage 51 | 52 | Add a snippet to your `.pre-commit-config.yaml` file in root of repository. 53 | 54 | ```yaml 55 | - repo: https://github.com/Azure4DevOps/check-azure-bicep 56 | rev: v0.2.1 # ${LATEST_SHA_OR_VERSION} 57 | hooks: 58 | - id: check-azure-bicep 59 | ``` 60 | 61 | ## Example local run 62 | 63 | run `pre-commit install` to set up the git hook scripts in your git repository # scan all modyfied miles before making commint (git hooks) 64 | or 65 | run `pre-commit run --all-files` # scanning all files 66 | 67 | at result all bicep files will or modified will be validated doing `az bicep build` 68 | 69 | ## Example Azure Pipelines usage `azure-pipelines-ci.yml` 70 | 71 | ```yaml 72 | pool: 73 | vmImage: "ubuntu-latest" 74 | steps: 75 | - script: | 76 | pip install pre-commit 77 | pre-commit --version 78 | pre-commit run --all-files 79 | displayName: Execute pre-commit 80 | ``` 81 | 82 | ## Example Github Workflow usage `github-action-ci.yml` 83 | 84 | ```yaml 85 | build: 86 | runs-on: ubuntu-latest 87 | steps: 88 | - name: Execute pre-commit 89 | run: | 90 | pip install pre-commit 91 | pre-commit --version 92 | pre-commit run --all-files 93 | ``` 94 | 95 | ## 📄 License 96 | 97 | This project is distributed under the terms of the [MIT](https://opensource.org/licenses/MIT) license. 98 | -------------------------------------------------------------------------------- /az_bicep_build.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | #$in = Get-ChildItem -Recurse -Filter "*.bicep" 3 | param([switch] $noupgrade ) 4 | $in = $args 5 | 6 | $error_azbuild = $false; 7 | az bicep version 8 | 9 | if (! $noupgrade) { 10 | az bicep upgrade 11 | } 12 | foreach ($b in $in) { 13 | $a = az bicep build --stdout --file $b 14 | if ( $LASTEXITCODE -eq 0 ) { 15 | } 16 | else { 17 | $error_azbuild = $true 18 | } 19 | } 20 | if ( $error_azbuild -eq $true ) { 21 | Exit 25 22 | } 23 | -------------------------------------------------------------------------------- /az_bicep_format.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | #$in = Get-ChildItem -Recurse -Filter "*.bicep" 3 | param([switch] $noupgrade ) 4 | $in = $args 5 | 6 | $error_azbuild = $false; 7 | az bicep version 8 | 9 | if (! $noupgrade) { 10 | az bicep upgrade 11 | } 12 | foreach ($b in $in) { 13 | $a = az bicep format --stdout --file $b 14 | if ( $LASTEXITCODE -eq 0 ) { 15 | } 16 | else { 17 | $error_azbuild = $true 18 | } 19 | } 20 | if ( $error_azbuild -eq $true ) { 21 | Exit 25 22 | } -------------------------------------------------------------------------------- /check-azure-bicep.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": {} 8 | } 9 | -------------------------------------------------------------------------------- /checkazurebiceppython/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import argparse 3 | import glob 4 | import subprocess 5 | import sys 6 | 7 | 8 | def az_bicep_build(): 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument('-noupgrade', action='store_true') 11 | args = parser.parse_args(['-noupgrade']) 12 | 13 | biceps_version = subprocess.run( 14 | ["az", "bicep", "version"], stdout=subprocess.PIPE, text=True, shell=True) 15 | if not args.noupgrade: 16 | biceps_version = subprocess.run( 17 | ["az", "bicep", "upgrade"], stdout=subprocess.PIPE, text=True, shell=True) 18 | # print(biceps_version.stdout) 19 | 20 | # print(glob.glob("./**/*.bicep", recursive=True)) 21 | any_error = None 22 | for bicep_file in glob.glob("./**/*.bicep", recursive=True): 23 | result = subprocess.run(["az", "bicep", "build", "--stdout", 24 | "--file", bicep_file], shell=True, capture_output=True) 25 | 26 | if result.stderr: 27 | print(result.stderr) 28 | any_error = True 29 | 30 | if any_error: 31 | sys.exit(25) 32 | 33 | 34 | def az_bicep_format(): 35 | parser = argparse.ArgumentParser() 36 | parser.add_argument('--noupgrade', action='store_true') 37 | args = parser.parse_args(['--noupgrade']) 38 | 39 | biceps_version = subprocess.run( 40 | ["az", "bicep", "version"], stdout=subprocess.PIPE, text=True, shell=True) 41 | if not args.noupgrade: 42 | biceps_version = subprocess.run( 43 | ["az", "bicep", "upgrade"], stdout=subprocess.PIPE, text=True, shell=True) 44 | # print(biceps_version.stdout) 45 | 46 | # print(glob.glob("./**/*.bicep", recursive=True)) 47 | any_error = None 48 | for bicep_file in glob.glob("./**/*.bicep", recursive=True): 49 | result = subprocess.run( 50 | ["az", "bicep", "format", "--file", bicep_file], shell=False, capture_output=True) 51 | 52 | if result.stderr: 53 | print(result.stderr) 54 | any_error = True 55 | 56 | if any_error: 57 | sys.exit(25) 58 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | azure-cli 2 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | import glob 3 | import subprocess 4 | import sys 5 | 6 | def get_project_requirements() -> str: 7 | with open(f"requirements.txt", "r") as f: 8 | return f.read() 9 | 10 | def az_bicep_build(): 11 | 12 | biceps_version = subprocess.run(["az", "bicep", "version"], stdout=subprocess.PIPE, text=True, shell=True) 13 | biceps_version = subprocess.run(["az", "bicep", "upgrade"], stdout=subprocess.PIPE, text=True, shell=True) 14 | #print(biceps_version.stdout) 15 | 16 | #print(glob.glob("./**/*.bicep", recursive=True)) 17 | any_error = None 18 | for bicep_file in glob.glob("./**/*.bicep", recursive=True): 19 | result = subprocess.run(["az", "bicep", "build", "--stdout", "--file", bicep_file], shell=True, capture_output=True) 20 | 21 | if result.stderr: 22 | print(result.stderr) 23 | any_error = True 24 | 25 | if any_error: 26 | sys.exit(25) 27 | 28 | def az_bicep_format(): 29 | 30 | biceps_version = subprocess.run(["az", "bicep", "version"], stdout=subprocess.PIPE, text=True, shell=True) 31 | biceps_version = subprocess.run(["az", "bicep", "upgrade"], stdout=subprocess.PIPE, text=True, shell=True) 32 | #print(biceps_version.stdout) 33 | 34 | #print(glob.glob("./**/*.bicep", recursive=True)) 35 | any_error = None 36 | for bicep_file in glob.glob("./**/*.bicep", recursive=True): 37 | result = subprocess.run(["az", "bicep", "format", "--stdout", "--file", bicep_file], shell=True, capture_output=True) 38 | 39 | if result.stderr: 40 | print(result.stderr) 41 | any_error = True 42 | 43 | if any_error: 44 | sys.exit(25) 45 | 46 | setuptools.setup( 47 | name="check-azure-bicep-python", 48 | description="check-azure-bicep-python", 49 | long_description_content_type="text/markdown", 50 | url="https://github.com/Azure4DevOps/check-azure-bicep", 51 | python_requires="==3.10.*", 52 | license="MIT", 53 | packages=setuptools.find_packages( 54 | include=["*"], 55 | ), 56 | install_requires=get_project_requirements(), 57 | entry_points={ 58 | "console_scripts": [ 59 | "entry_az_bicep_build=checkazurebiceppython:az_bicep_build", 60 | "entry_az_bicep_format=checkazurebiceppython:az_bicep_format", 61 | ] 62 | }, 63 | ) 64 | -------------------------------------------------------------------------------- /test.bicep: -------------------------------------------------------------------------------- 1 | @description('Specifies region of RG.') 2 | param location string = resourceGroup().location 3 | 4 | @description('Storage Account type') 5 | @allowed([ 6 | 'Standard_LRS' 7 | 'Standard_GRS' 8 | 'Standard_ZRS' 9 | 'Premium_LRS' 10 | ]) 11 | param storageAccountType string = 'Standard_LRS' 12 | 13 | param instLocation array = [ 14 | 'westeurope' 15 | ] 16 | 17 | param instName array = [ 18 | 'euw' 19 | ] 20 | 21 | @description('Type of environment where this deployment should occur.') 22 | @allowed([ 23 | 'pr' 24 | 'dev' 25 | 'prod' 26 | 'jnno' 27 | 'test' 28 | ]) 29 | param environmentType string = 'dev' 30 | 31 | @description('Name of Application.') 32 | param applicationName string = 'ga2022' 33 | param storageConfig object = { 34 | kind: 'StorageV2' 35 | accessTier: 'Hot' 36 | httpsTrafficOnlyEnabled: true 37 | } 38 | param nameConv object = { 39 | storageAccountName: 'stacc' 40 | hostingPlanName: 'plan' 41 | siteName: 'site' 42 | trafficManagerName: 'tmanager' 43 | appins: 'appins' 44 | } 45 | 46 | var namestorage = '${applicationName}${environmentType}' 47 | var name = '${applicationName}-${environmentType}' 48 | 49 | resource namestorage_instName_nameConv_storageAccountName 'Microsoft.Storage/storageAccounts@2021-04-01' = [for (item, i) in instLocation: { 50 | sku: { 51 | name: storageAccountType 52 | } 53 | kind: storageConfig.kind 54 | properties: { 55 | supportsHttpsTrafficOnly: storageConfig.httpsTrafficOnlyEnabled 56 | accessTier: storageConfig.accessTier 57 | encryption: { 58 | services: { 59 | blob: { 60 | enabled: true 61 | } 62 | file: { 63 | enabled: true 64 | } 65 | } 66 | keySource: 'Microsoft.Storage' 67 | } 68 | } 69 | tags: { 70 | displayName: 'Array Storage Accounts' 71 | } 72 | location: item 73 | name: '${namestorage}${instName[i]}${nameConv.storageAccountName}' 74 | }] 75 | 76 | resource name_instName_nameConv_hostingPlanName 'Microsoft.Web/serverfarms@2021-03-01' = [for (item, i) in instLocation: { 77 | sku: { 78 | name: 'Y1' //Dynamic 79 | } 80 | kind: 'linux' 81 | location: item 82 | name: '${name}-${instName[i]}${nameConv.hostingPlanName}' 83 | }] 84 | 85 | resource name_instName_nameConv_siteName 'Microsoft.Web/sites@2020-12-01' = [for (item, i) in instLocation: { 86 | name: '${name}-${instName[i]}${nameConv.siteName}' 87 | location: item 88 | dependsOn: [ 89 | name_instName_nameConv_hostingPlanName 90 | ] 91 | tags: { 92 | displayName: 'Array Sites' 93 | } 94 | kind: 'functionapp' 95 | properties: { 96 | httpsOnly: true 97 | serverFarmId: resourceId('Microsoft.Web/serverfarms', '${name}-${instName[i]}${nameConv.hostingPlanName}') 98 | siteConfig: { 99 | appSettings: [ 100 | { 101 | name: 'AzureWebJobsStorage' 102 | value: 'DefaultEndpointsProtocol=https;AccountName=${namestorage}${instName[i]}${nameConv.storageAccountName};AccountKey=${listKeys(namestorage_instName_nameConv_storageAccountName[i].id, namestorage_instName_nameConv_storageAccountName[i].apiVersion).keys[0].value};EndpointSuffix=${environment().suffixes.storage}' 103 | } 104 | { 105 | name: 'FUNCTIONS_WORKER_RUNTIME' 106 | value: 'dotnet' 107 | } 108 | { 109 | name: 'FUNCTIONS_EXTENSION_VERSION' 110 | value: '~4' 111 | } 112 | { 113 | name: 'APPINSIGHTS_INSTRUMENTATIONKEY' 114 | value: name_global_nameConv_appins.properties.InstrumentationKey 115 | } 116 | { 117 | name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' 118 | value: 'InstrumentationKey=${name_global_nameConv_appins.properties.InstrumentationKey}' 119 | } 120 | ] 121 | } 122 | } 123 | 124 | }] 125 | 126 | resource trafficManagerProfile 'Microsoft.Network/trafficManagerProfiles@2018-08-01' = { 127 | name: '${name}-global-${nameConv.trafficManagerName}' 128 | location: 'global' 129 | dependsOn: [ 130 | name_instName_nameConv_siteName 131 | ] 132 | properties: { 133 | profileStatus: 'Enabled' 134 | trafficRoutingMethod: 'Priority' 135 | dnsConfig: { 136 | relativeName: '${name}-global-${nameConv.trafficManagerName}' 137 | ttl: 30 138 | } 139 | monitorConfig: { 140 | protocol: 'HTTPS' 141 | port: 443 142 | path: '/api/IsAlive' 143 | } 144 | } 145 | } 146 | 147 | resource trafficManagerAzureEndpoint 'Microsoft.Network/trafficManagerProfiles/azureEndpoints@2018-08-01' = [for (item, i) in instLocation: { 148 | name: '${name}-${instName[i]}${nameConv.siteName}' 149 | parent: trafficManagerProfile 150 | dependsOn: [ 151 | name_instName_nameConv_siteName 152 | ] 153 | properties: { 154 | endpointMonitorStatus: 'Online' 155 | targetResourceId: resourceId('Microsoft.Web/sites', '${name}-${instName[i]}${nameConv.siteName}') 156 | } 157 | }] 158 | 159 | resource name_global_nameConv_appins 'Microsoft.Insights/components@2020-02-02' = { 160 | name: '${name}-global-${nameConv.appins}' 161 | location: location 162 | kind: 'web' 163 | properties: { 164 | Application_Type: 'web' 165 | publicNetworkAccessForIngestion: 'Enabled' 166 | publicNetworkAccessForQuery: 'Enabled' 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /tests/az_bicep_format_python_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import subprocess 3 | from unittest.mock import patch 4 | 5 | class TestBicepBuild(unittest.TestCase): 6 | 7 | def test_bicep_build(self): 8 | 9 | # mock the subprocess.run() function to return a version and upgrade output 10 | with patch('subprocess.run') as mock_run: 11 | mock_run.side_effect = [ 12 | subprocess.CompletedProcess(['az', 'bicep', 'version'], stdout=b"1.0.0\n", stderr=""), 13 | subprocess.CompletedProcess(['az', 'bicep', 'upgrade'], stdout=b"Upgrading Bicep CLI version 0.4.100 to 1.0.0\n", stderr="") 14 | ] 15 | 16 | # mock the glob.glob() function to return a list of bicep files 17 | with patch('glob.glob', return_value=['./path/to/example.bicep']): 18 | # run the code being tested 19 | result = subprocess.run(["python", "test.py"], shell=True, capture_output=True) 20 | 21 | # assert that the subprocess.run() function was called with the correct arguments 22 | mock_run.assert_any_call(['az', 'bicep', 'version'], stdout=subprocess.PIPE, text=True, shell=True) 23 | mock_run.assert_any_call(['az', 'bicep', 'upgrade'], stdout=subprocess.PIPE, text=True, shell=True) 24 | mock_run.assert_any_call(['az', 'bicep', 'build', '--stdout', '--file', './path/to/example.bicep'], shell=True, capture_output=True) 25 | 26 | # assert that the output is as expected 27 | self.assertEqual(result.returncode, 0, "Expected return code 0") 28 | self.assertEqual(result.stderr, b"", "Expected empty stderr") 29 | -------------------------------------------------------------------------------- /tests/az_bicep_format_python_test_integration.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import subprocess 3 | import os 4 | 5 | class TestBicepBuild(unittest.TestCase): 6 | 7 | @classmethod 8 | def setUpClass(cls): 9 | # create a test directory and change to it 10 | os.mkdir("test_dir") 11 | os.chdir("test_dir") 12 | 13 | # create some test bicep files 14 | with open("main.bicep", "w") as f: 15 | f.write('resource test_resource "Microsoft.Storage/storageAccounts@2021-04-01" = {\n name: "test"\n location: "eastus"\n sku: {\n name: "Standard_LRS"\n }\n}') 16 | 17 | with open("module/module.bicep", "w") as f: 18 | f.write('module test_module "./../module"\n') 19 | 20 | with open("module/module.json", "w") as f: 21 | f.write('{\n "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",\n "contentVersion": "1.0.0.0",\n "resources": []\n}') 22 | 23 | @classmethod 24 | def tearDownClass(cls): 25 | # change back to the original directory and remove the test directory 26 | os.chdir("..") 27 | os.rmdir("test_dir") 28 | 29 | def test_bicep_build(self): 30 | # run the bicep build command 31 | result = subprocess.run(["python", "test.py"], shell=True, capture_output=True) 32 | 33 | # assert that the output is as expected 34 | self.assertEqual(result.returncode, 0, "Expected return code 0") 35 | self.assertEqual(result.stderr, b"", "Expected empty stderr") 36 | self.assertIn(b"Resource 'test_resource' was built successfully.", result.stdout) 37 | self.assertIn(b"module.json: Finished successfully", result.stdout) 38 | -------------------------------------------------------------------------------- /tests/testfail.bicep: -------------------------------------------------------------------------------- 1 | @description('Specifies region of RG.') 2 | param location string = resourceGroup().location 3 | 4 | @description('Storage Account type') 5 | @allowed([ 6 | 'Standard_LRS' 7 | 'Standard_GRS' 8 | 'Standard_ZRS' 9 | 'Premium_LRS' 10 | ]) 11 | param storageAccountType string = 'Standard_LRS' 12 | 13 | param instLocation array = [ 14 | 'westeurope' 15 | ] 16 | param instName array = [ 17 | 'euw' 18 | ] 19 | 20 | @description('Type of environment where this deployment should occur.') 21 | @allowed([ 22 | 'pr' 23 | 'dev' 24 | 'prod' 25 | 'jnno' 26 | 'test' 27 | ]) 28 | param environmentType string = 'dev' 29 | 30 | @description('Name of Application.') 31 | param applicationName string = 'ga2022' 32 | param storageConfig object = { 33 | kind: 'StorageV2' 34 | accessTier: 'Hot' 35 | httpsTrafficOnlyEnabled: true 36 | } 37 | param nameConv object = { 38 | storageAccountName: 'stacc' 39 | hostingPlanName: 'plan' 40 | siteName: 'site' 41 | trafficManagerName: 'tmanager' 42 | appins: 'appins' 43 | } 44 | 45 | var namestorage = '${applicationName}${environmentType}' 46 | var name = '${applicationName}-${environmentType}' 47 | 48 | resource namestorage_instName_nameConv_storageAccountName 'Microsoft.Storage/storageAccounts@2021-04-01' = [for (item, i) in instLocation: { 49 | sku: { 50 | name: storageAccountType 51 | } 52 | kind: storageConfig.kind 53 | properties: { 54 | supportsHttpsTrafficOnly: storageConfig.httpsTrafficOnlyEnabled 55 | accessTier: storageConfig.accessTier 56 | encryption: { 57 | services: { 58 | blob: { 59 | enabled: true 60 | } 61 | file: { 62 | enabled: true 63 | } 64 | } 65 | keySource: 'Microsoft.Storage' 66 | } 67 | } 68 | tags: { 69 | displayName: 'Array Storage Accounts' 70 | } 71 | location: item 72 | name: '${namestorage}${instName[i]}${nameConv.storageAccountName}' 73 | }] 74 | 75 | resource name_instName_nameConv_hostingPlanName 'Microsoft.Web/serverfarms@2021-03-01' = [for (item, i) in instLocation: { 76 | sku: { 77 | name: 'Y1' //Dynamic 78 | } 79 | kind: 'linux' 80 | location: item 81 | name: '${name}-${instName[i]}${nameConv.hostingPlanName}' 82 | }] 83 | 84 | resource name_instName_nameConv_siteName 'Microsoft.Web/sites@2020-12-01' = [for (item, i) in instLocation: { 85 | name: '${name}-${instName[i]}${nameConv.siteName}' 86 | location: item 87 | dependsOn: [ 88 | name_instName_nameConv_hostingPlanName 89 | ] 90 | tags: { 91 | displayName: 'Array Sites' 92 | } 93 | kind: 'functionapp' 94 | properties: { 95 | httpsOnly: true 96 | serverFarmId: resourceId('Microsoft.Web/serverfarms', '${name}-${instName[i]}${nameConv.hostingPlanName}') 97 | siteConfig: { 98 | appSettings: [ 99 | { 100 | name: 'AzureWebJobsStorage' 101 | value: 'DefaultEndpointsProtocol=https;AccountName=${namestorage}${instName[i]}${nameConv.storageAccountName};AccountKey=${listKeys(namestorage_instName_nameConv_storageAccountName[i].id, namestorage_instName_nameConv_storageAccountName[i].apiVersion).keys[0].value};EndpointSuffix=${environment().suffixes.storage}' 102 | } 103 | { 104 | name: 'FUNCTIONS_WORKER_RUNTIME' 105 | value: 'dotnet' 106 | } 107 | { 108 | name: 'FUNCTIONS_EXTENSION_VERSION' 109 | value: '~4' 110 | } 111 | { 112 | name: 'APPINSIGHTS_INSTRUMENTATIONKEY' 113 | value: name_global_nameConv_appins.properties.InstrumentationKey 114 | } 115 | { 116 | name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' 117 | value: 'InstrumentationKey=${name_global_nameConv_appins.properties.InstrumentationKey}' 118 | } 119 | ] 120 | } 121 | } 122 | 123 | }] 124 | 125 | resource trafficManagerProfile 'Microsoft.Network/trafficManagerProfiles@2018-08-01' = { 126 | name: '${name}-global-${nameConv.trafficManagerName}' 127 | location: 'global' 128 | dependsOn: [ 129 | name_instName_nameConv_siteName 130 | ] 131 | properties: { 132 | profileStatus: 'Enabled' 133 | trafficRoutingMethod: 'Priority' 134 | dnsConfig: { 135 | relativeName: '${name}-global-${nameConv.trafficManagerName}' 136 | ttl: 30 137 | } 138 | monitorConfig: { 139 | protocol: 'HTTPS' 140 | port: 443 141 | path: '/api/IsAlive' 142 | } 143 | } 144 | } 145 | 146 | resource trafficManagerAzureEndpoint 'Microsoft.Network/trafficManagerProfiles/azureEndpoints@2018-08-01' = [for (item, i) in instLocation: { 147 | name: '${name}-${instName[i]}${nameConv.siteName}' 148 | parent: trafficManagerProfile 149 | dependsOn: [ 150 | name_instName_nameConv_siteName 151 | ] 152 | properties: { 153 | endpointMonitorStatus: 'Online' 154 | targetResourceId: resourceId('Microsoft.Web/sites', '${name}-${instName[i]}${nameConv.siteName}') 155 | } 156 | }] 157 | 158 | resource name_global_nameConv_appins 'Microsoft.Insights/components@2020-02-02' = { 159 | name: '${name}-global-${nameConv.appins}' 160 | location: location 161 | kind: 'web' 162 | properties: { 163 | Application_Type: 'web' 164 | publicNetworkAccessForIngestion: 'Enabled' 165 | publicNetworkAccessForQuery: 'Enabled' 166 | } 167 | } 168 | --------------------------------------------------------------------------------