Building Azure DevOps YAML pipelines and continuously adding the same pipeline.yaml file? Over time; this file can grow and grow – copy and pasting the same job/task but changing variables? I recommend that you have a look at creating templates within your Azure DevOps pipelines to template common jobs/tasks that you can reuse within other pipelines!
Why create templates?
Some reasons into why I consider creating templates as part of my Azure DevOps pipelines:-
- Reusability
- Avoids duplication
- Reduces complexity and size of creating a single pipeline
- Set structure and pattern that I can follow throughout my pipelines
- Used as a guide to create further stages
- Saves time and allows me to create generic templates that I can use on multiple projects
- Adding/removing a change in one file rather than a number of stages – changing the same config each time
I recommend checking out this blog post, Azure DevOps Pipelines – Keeping your pipelines DRY (Don’t Repeat Yourself) – it is following my thoughts and suggestions of keeping your pipelines DRY!
Azure DevOps Pipeline with no templates
First, lets have a look at an Azure DevOps Pipeline that doesn’t use templates, as you can see – one huge YAML file, I would not call this a clean approach. (GitHub URL)
Over time, this will grow – this is when I recommend to introduce templating. A template dedicated to each task!
name: $(BuildDefinitionName)_$(date:yyyyMMdd)$(rev:.r)
trigger: none
pr: none
variables:
- group: azurefestivecalendar-production
- name: backendServiceArm
value: 'tamopstf2'
- name: backendAzureRmResourceGroupName
value: 'tamopstfstates'
- name: backendAzureRmStorageAccountName
value: 'tfstatedevops'
- name: backendAzureRmContainerName
value: 'azuredevopstemplates'
- name: backendAzureRmKey
value: 'terraform.tfstate'
- name: environment
value: 'production'
stages :
- stage: validate
jobs:
- job: validate
continueOnError: false
steps:
- task: TerraformInstaller@0
displayName: 'install'
inputs:
terraformVersion: '0.13.3'
- task: TerraformTaskV1@0
displayName: 'init'
inputs:
provider: 'azurerm'
command: 'init'
backendServiceArm: 'tamopstf'
backendAzureRmResourceGroupName: '${{ variables.backendAzureRmResourceGroupName}}'
backendAzureRmStorageAccountName: '${{ variables.backendAzureRmStorageAccountName}}'
backendAzureRmContainerName: '${{ variables.backendAzureRmContainerName }}'
backendAzureRmKey: 'terraform.tfstate'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
- task: TerraformTaskV1@0
displayName: 'validate'
inputs:
provider: 'azurerm'
command: 'validate'
- stage: plan
dependsOn: [validate]
condition: succeeded('validate')
jobs:
- job: terraform_plan_develop
steps:
- checkout: self
- task: TerraformInstaller@0
displayName: 'install'
inputs:
terraformVersion: '0.13.3'
- task: TerraformTaskV1@0
displayName: 'init'
inputs:
provider: 'azurerm'
command: 'init'
backendServiceArm: 'tamopstf'
backendAzureRmResourceGroupName: '${{ variables.backendAzureRmResourceGroupName}}'
backendAzureRmStorageAccountName: '${{ variables.backendAzureRmStorageAccountName}}'
backendAzureRmContainerName: '${{ variables.backendAzureRmContainerName }}'
backendAzureRmKey: 'terraform.tfstate'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
- task: TerraformTaskV1@0
displayName: 'plan'
inputs:
provider: 'azurerm'
command: 'plan'
commandOptions: '-input=false -var-file="../$(Environment)/$(Environment).tfvars"'
environmentServiceNameAzureRM: 'tamopstf'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
- stage: apply
dependsOn: [plan]
condition: succeeded('plan')
jobs:
- job: terraform_apply_production
steps:
- checkout: self
- task: TerraformInstaller@0
displayName: 'install'
inputs:
terraformVersion: '0.13.3'
- task: TerraformTaskV1@0
displayName: 'init'
inputs:
provider: 'azurerm'
command: 'init'
backendServiceArm: 'tamopstf'
backendAzureRmResourceGroupName: '${{ variables.backendAzureRmResourceGroupName}}'
backendAzureRmStorageAccountName: '${{ variables.backendAzureRmStorageAccountName}}'
backendAzureRmContainerName: '${{ variables.backendAzureRmContainerName }}'
backendAzureRmKey: 'terraform.tfstate'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
- task: TerraformTaskV1@0
displayName: 'plan'
inputs:
provider: 'azurerm'
command: 'plan'
commandOptions: '-input=false -var-file="../$(Environment)/$(Environment).tfvars"'
environmentServiceNameAzureRM: 'tamopstf'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
- task: TerraformTaskV1@0
displayName: 'apply'
inputs:
provider: 'azurerm'
command: 'apply'
commandOptions: '-input=false -auto-approve -var-file="../$(Environment)/$(Environment).tfvars"'
environmentServiceNameAzureRM: 'tamopstf'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
- stage: test
dependsOn: [apply]
condition: succeeded('apply')
jobs:
- job: Inspec_Testing
steps:
- task: UseRubyVersion@0
displayName: 'Install Ruby'
inputs:
versionSpec: '>= 2.5'
addToPath: true
- script: gem install inspec-bin
displayName: 'Install inspec-bin'
- task: Bash@3
displayName: 'Run inspec tests'
inputs:
targetType: inline
script: |
export AZURE_SUBSCRIPTION_ID=$(AZURE_SUBSCRIPTION_ID)
export AZURE_CLIENT_ID=$(AZURE_CLIENT_ID)
export AZURE_CLIENT_SECRET=$(AZURE_CLIENT_SECRET)
export AZURE_TENANT_ID=$(AZURE_TENANT_ID)
inspec exec ./azure-inspec-tests/ -t azure:// --chef-license=accept --reporter cli junit:inspectestresults.xml
- task: PublishTestResults@2
displayName: Publish inspec test results
condition: succeededOrFailed()
inputs:
testResultsFiles: '**/inspectestresults.xml'
mergeTestResults: true
- stage: bash
dependsOn: [apply]
condition: succeeded('apply')
jobs:
- job: bash_echo
steps:
- task: Bash@3
displayName: 'Echo Test'
inputs:
targetType: inline
script: |
Echo "Test Script!"
- stage: cli
dependsOn: [apply]
condition: succeeded('apply')
jobs:
- job: azcli_resourcegroup_create
steps:
- task: AzureCLI@2
displayName: 'Deploy Resource Group'
inputs:
azureSubscription: 'tamopstf'
scriptType: bash
scriptLocation: inlineScript
addSpnToEnvironment: true
inlineScript: |
#!/bin/bash
az group create -l uksouth -n bicep-rg
Identifying jobs/tasks that can be templated
Lets identity common tasks within the pipeline:-
- Terraform Init/Validate
- Terraform Plan
- Terraform Apply
- Inspec Testing
- Bash Script
- Azure CLI
Current folder structure
Azure-DevOps-Pipelines-Using-Templates
└── azure-inspec-tests
└── pipelines
└── production
└── terraform
I will add a folder into pipelines – to store my templates
Azure-DevOps-Pipelines-Using-Templates
└── azure-inspec-tests
└── pipelines
└── templates
└── production
└── terraform
How are templates referenced within Azure DevOps Pipelines?
Using – template reference , template below
stages :
- stage: terraform_validate
jobs:
- template: templates/terraform-validate.yaml
Moving pipeline from one file to using Azure DevOps Pipeline Templates
I will now show a template for each task identified:
- Terraform Init/Validate
- Terraform Plan
- Terraform Apply
- Inspec Testing
- Bash Script
- Azure CLI
jobs:
- job: terraform_validate
continueOnError: false
steps:
- task: TerraformInstaller@0
displayName: 'install'
inputs:
terraformVersion: '${{ parameters.terraform_version }}'
- task: TerraformTaskV1@0
displayName: 'init'
inputs:
provider: 'azurerm'
command: 'init'
backendServiceArm: '${{ parameters.backendServiceArm }}'
backendAzureRmResourceGroupName: '${{ parameters.backendAzureRmResourceGroupName }}'
backendAzureRmStorageAccountName: '${{ parameters.backendAzureRmStorageAccountName }}'
backendAzureRmContainerName: '${{ parameters.backendAzureRmContainerName }}'
backendAzureRmKey: '${{ parameters.backendAzureRmKey }}'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
- task: TerraformTaskV1@0
displayName: 'validate'
inputs:
provider: 'azurerm'
command: 'validate'
jobs:
- job: terraform_plan
steps:
- task: TerraformInstaller@0
displayName: 'install'
inputs:
terraformVersion: '${{ parameters.terraform_version }}'
- task: TerraformTaskV1@0
displayName: 'init'
inputs:
provider: 'azurerm'
command: 'init'
backendServiceArm: '${{ parameters.backendServiceArm }}'
backendAzureRmResourceGroupName: '${{ parameters.backendAzureRmResourceGroupName }}'
backendAzureRmStorageAccountName: '${{ parameters.backendAzureRmStorageAccountName }}'
backendAzureRmContainerName: '${{ parameters.backendAzureRmContainerName }}'
backendAzureRmKey: '${{ parameters.backendAzureRmKey }}'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
- task: TerraformTaskV1@0
displayName: 'plan'
inputs:
provider: 'azurerm'
command: 'plan'
commandOptions: '-input=false -var-file="../vars/${{ parameters.environment }}/${{ parameters.environment }}.tfvars"'
environmentServiceNameAzureRM: '${{ parameters.backendServiceArm }}'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
jobs:
- job: terraform_apply
steps:
- task: TerraformInstaller@0
displayName: 'install'
inputs:
terraformVersion: '${{ parameters.terraform_version }}'
- task: TerraformTaskV1@0
displayName: 'init'
inputs:
provider: 'azurerm'
command: 'init'
backendServiceArm: '${{ parameters.backendServiceArm }}'
backendAzureRmResourceGroupName: '${{ parameters.backendAzureRmResourceGroupName }}'
backendAzureRmStorageAccountName: '${{ parameters.backendAzureRmStorageAccountName }}'
backendAzureRmContainerName: '${{ parameters.backendAzureRmContainerName }}'
backendAzureRmKey: '${{ parameters.backendAzureRmKey }}'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
- task: TerraformTaskV1@0
displayName: 'plan'
inputs:
provider: 'azurerm'
command: 'plan'
commandOptions: '-input=false -var-file="../vars/${{ parameters.environment }}/${{ parameters.environment }}.tfvars"'
environmentServiceNameAzureRM: '${{ parameters.backendServiceArm }}'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
- task: TerraformTaskV1@0
displayName: 'apply'
inputs:
provider: 'azurerm'
command: 'apply'
commandOptions: '-input=false -auto-approve -var-file="../vars/${{ parameters.environment }}/${{ parameters.environment }}.tfvars"'
environmentServiceNameAzureRM: '${{ parameters.backendServiceArm }}'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
jobs:
- job: Inspec_Testing
steps:
- task: UseRubyVersion@0
displayName: 'Install Ruby'
inputs:
versionSpec: '${{ parameters.ruby_versionspec }}'
addToPath: true
- script: gem install inspec-bin
displayName: 'Install inspec-bin'
- task: Bash@3
displayName: 'Run inspec tests'
inputs:
targetType: inline
script: |
export AZURE_SUBSCRIPTION_ID=$('${{ parameters.AZURE_SUBSCRIPTION_ID }}')
export AZURE_CLIENT_ID=$('${{ parameters.AZURE_CLIENT_ID }}')
export AZURE_CLIENT_SECRET=$('${{ parameters.AZURE_CLIENT_SECRET }}')
export AZURE_TENANT_ID=$('${{ parameters.AZURE_TENANT_ID }}')
inspec exec ./azure-inspec-tests/ -t azure:// --chef-license=accept --reporter cli junit:inspectestresults.xml
- task: PublishTestResults@2
displayName: Publish inspec test results
condition: succeededOrFailed()
inputs:
testResultsFiles: '**/inspectestresults.xml'
mergeTestResults: true
jobs:
- job: bash_echo
steps:
- task: Bash@3
displayName: 'Echo Test'
inputs:
targetType: inline
script: |
Echo "${{ parameters.bash_input }}"
jobs:
- job: azcli_resourcegroup_create
steps:
- task: AzureCLI@2
displayName: 'Deploy Resource Group'
inputs:
azureSubscription: 'tamopstf'
scriptType: bash
scriptLocation: inlineScript
addSpnToEnvironment: true
inlineScript: |
#!/bin/bash
az group create -l uksouth -n ${{ parameters.resource_group }}
Awesome, all the jobs/tasks have now been templated, how does the main Azure DevOps pipeline now look?
name: $(BuildDefinitionName)_$(date:yyyyMMdd)$(rev:.r)
trigger: none
pr: none
variables:
- group: azurefestivecalendar-production
- name: backendServiceArm
value: 'tamopstf2'
- name: backendAzureRmResourceGroupName
value: 'tamopstfstates'
- name: backendAzureRmStorageAccountName
value: 'tfstatedevops'
- name: backendAzureRmContainerName
value: 'azuredevopstemplates'
- name: backendAzureRmKey
value: 'terraform.tfstate'
- name: environment
value: 'production'
- name: terraform_version
value: '0.13.3'
- name: ruby_versionspec
value: '>= 2.5'
stages :
- stage: terraform_validate
jobs:
- template: templates/terraform-validate.yaml
parameters:
backendServiceArm: ${{ variables.backendServiceArm }}
backendAzureRmResourceGroupName: ${{ variables.backendAzureRmResourceGroupName }}
backendAzureRmStorageAccountName: ${{ variables.backendAzureRmStorageAccountName }}
backendAzureRmContainerName: ${{ variables.backendAzureRmContainerName }}
backendAzureRmKey: ${{ variables.backendAzureRmKey }}
environment: ${{ variables.environment }}
terraform_version: ${{ variables.terraform_version }}
- stage: terraform_plan
dependsOn: [terraform_validate]
condition: succeeded('terraform_validate')
jobs:
- template: templates/terraform-plan.yaml
parameters:
backendServiceArm: ${{ variables.backendServiceArm }}
backendAzureRmResourceGroupName: ${{ variables.backendAzureRmResourceGroupName }}
backendAzureRmStorageAccountName: ${{ variables.backendAzureRmStorageAccountName }}
backendAzureRmContainerName: ${{ variables.backendAzureRmContainerName }}
backendAzureRmKey: ${{ variables.backendAzureRmKey }}
environment: ${{ variables.environment }}
terraform_version: ${{ variables.terraform_version }}
- stage: terraform_apply
dependsOn: [terraform_plan]
condition: succeeded('terraform_plan')
jobs:
- template: templates/terraform-apply.yaml
parameters:
backendServiceArm: ${{ variables.backendServiceArm }}
backendAzureRmResourceGroupName: ${{ variables.backendAzureRmResourceGroupName }}
backendAzureRmStorageAccountName: ${{ variables.backendAzureRmStorageAccountName }}
backendAzureRmContainerName: ${{ variables.backendAzureRmContainerName }}
backendAzureRmKey: ${{ variables.backendAzureRmKey }}
environment: ${{ variables.environment }}
terraform_version: ${{ variables.terraform_version }}
- stage: inspec_testing
dependsOn: [terraform_apply]
condition: succeeded('terraform_apply')
jobs:
- template: templates/inspec-testing.yaml
parameters:
ruby_versionspec: ${{ variables.backendServiceArm }}
AZURE_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID)
AZURE_CLIENT_ID: $(AZURE_CLIENT_ID)
AZURE_CLIENT_SECRET: $(AZURE_CLIENT_SECRET)
AZURE_TENANT_ID: $(AZURE_TENANT_ID)
- stage: bash
dependsOn: [terraform_apply]
condition: succeeded('terraform_apply')
jobs:
- template: templates/bash-script.yaml
parameters:
bash_input: "Test Script!"
- stage: cli
dependsOn: [terraform_apply]
condition: succeeded('terraform_apply')
jobs:
- template: templates/az-cli.yaml
parameters:
resource_group: "bicep-rg"
Notice the difference? The pipeline is now alot cleaner with no bloating!
I have created a number of generic templates that can now be used for the associated tasks within any additional pipelines – reusability! Awesome 🙂
Using this approach will assist you in reducing additional effort required creating new pipelines as you will have a number of tasks already templated!
Hi Thomas,
How are you doing? Hoping all is good. Much appreciated your effort and you’re my mentor and not only to me too many tech guys . Need your support /Suggestion on the inspec-azure azure devops pipeline.Getting the below error while running the pipeline . Would you please assist am i missing here anything?
Thanks in advance. Please find my pipeline logs.
2022-01-25T20:45:29.4482978Z ##[section]Starting: Run inspec tests
2022-01-25T20:45:29.4571490Z ==============================================================================
2022-01-25T20:45:29.4571771Z Task : Bash
2022-01-25T20:45:29.4572012Z Description : Run a Bash script on macOS, Linux, or Windows
2022-01-25T20:45:29.4572246Z Version : 3.198.0
2022-01-25T20:45:29.4572451Z Author : Microsoft Corporation
2022-01-25T20:45:29.4572742Z Help : https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/bash
2022-01-25T20:45:29.4573077Z ==============================================================================
2022-01-25T20:45:29.5855046Z Generating script.
2022-01-25T20:45:29.5885228Z ========================== Starting Command Output ===========================
2022-01-25T20:45:29.5909067Z [command]/usr/bin/bash /home/vsts/work/_temp/ed9af8a9-4bae-41ba-8b01-765713ec80a5.sh
2022-01-25T20:45:32.8402781Z +———————————————+
2022-01-25T20:45:32.8403842Z ✔ 1 product license accepted.
2022-01-25T20:45:32.8404893Z +———————————————+
2022-01-25T20:45:35.3032554Z /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/activesupport-7.0.1/lib/active_support/xml_mini.rb:184:in `current_thread_backend’: uninitialized constant ActiveSupport::XmlMini::IsolatedExecutionState (NameError)
2022-01-25T20:45:35.3033715Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/activesupport-7.0.1/lib/active_support/xml_mini.rb:103:in `backend=’
2022-01-25T20:45:35.3034565Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/activesupport-7.0.1/lib/active_support/xml_mini.rb:201:in `’
2022-01-25T20:45:35.3035438Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/activesupport-7.0.1/lib/active_support/xml_mini.rb:11:in `’
2022-01-25T20:45:35.3036219Z from :85:in `require’
2022-01-25T20:45:35.3037002Z from :85:in `require’
2022-01-25T20:45:35.3037818Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/activesupport-7.0.1/lib/active_support/core_ext/hash/conversions.rb:3:in `’
2022-01-25T20:45:35.3038613Z from :85:in `require’
2022-01-25T20:45:35.3039350Z from :85:in `require’
2022-01-25T20:45:35.3040155Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/activesupport-7.0.1/lib/active_support/core_ext/hash.rb:3:in `’
2022-01-25T20:45:35.3040914Z from :85:in `require’
2022-01-25T20:45:35.3041666Z from :85:in `require’
2022-01-25T20:45:35.3042416Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/dsl_shared.rb:33:in `require’
2022-01-25T20:45:35.3043014Z from libraries/backend/azure_require.rb:8:in `create’
2022-01-25T20:45:35.3043674Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/dsl_shared.rb:47:in `eval’
2022-01-25T20:45:35.3044418Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/dsl_shared.rb:47:in `require’
2022-01-25T20:45:35.3045280Z from libraries/azure_backend.rb:1:in `create’
2022-01-25T20:45:35.3045908Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/dsl_shared.rb:47:in `eval’
2022-01-25T20:45:35.3046664Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/dsl_shared.rb:47:in `require’
2022-01-25T20:45:35.3047426Z from libraries/azure_graph_generic_resource.rb:1:in `create’
2022-01-25T20:45:35.3048097Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/dsl_shared.rb:47:in `eval’
2022-01-25T20:45:35.3048835Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/dsl_shared.rb:47:in `require’
2022-01-25T20:45:35.3049502Z from libraries/azure_active_directory_domain_service.rb:1:in `load_with_context’
2022-01-25T20:45:35.3050232Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/profile_context.rb:170:in `instance_eval’
2022-01-25T20:45:35.3051054Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/profile_context.rb:170:in `load_with_context’
2022-01-25T20:45:35.3051874Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/profile_context.rb:159:in `load_library_file’
2022-01-25T20:45:35.3052698Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/profile_context.rb:144:in `block in load_libraries’
2022-01-25T20:45:35.3053504Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/profile_context.rb:143:in `each’
2022-01-25T20:45:35.3054289Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/profile_context.rb:143:in `load_libraries’
2022-01-25T20:45:35.3055082Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/profile.rb:376:in `load_libraries’
2022-01-25T20:45:35.3055867Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/profile.rb:369:in `block in load_libraries’
2022-01-25T20:45:35.3056636Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/profile.rb:350:in `each’
2022-01-25T20:45:35.3057401Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/profile.rb:350:in `each_with_index’
2022-01-25T20:45:35.3058171Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/profile.rb:350:in `load_libraries’
2022-01-25T20:45:35.3058937Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/runner.rb:108:in `block in load’
2022-01-25T20:45:35.3059669Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/runner.rb:102:in `each’
2022-01-25T20:45:35.3060414Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/runner.rb:102:in `load’
2022-01-25T20:45:35.3061132Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/runner.rb:136:in `run’
2022-01-25T20:45:35.3061863Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/cli.rb:304:in `exec’
2022-01-25T20:45:35.3062574Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/thor-1.2.1/lib/thor/command.rb:27:in `run’
2022-01-25T20:45:35.3063290Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/thor-1.2.1/lib/thor/invocation.rb:127:in `invoke_command’
2022-01-25T20:45:35.3064003Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/thor-1.2.1/lib/thor.rb:392:in `dispatch’
2022-01-25T20:45:35.3067018Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/thor-1.2.1/lib/thor/base.rb:485:in `start’
2022-01-25T20:45:35.3067937Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-core-4.52.9/lib/inspec/base_cli.rb:35:in `start’
2022-01-25T20:45:35.3068660Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/inspec-bin-4.52.9/bin/inspec:11:in `’
2022-01-25T20:45:35.3069272Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/bin/inspec:25:in `load’
2022-01-25T20:45:35.3069792Z from /opt/hostedtoolcache/Ruby/3.0.3/x64/bin/inspec:25:in `’
2022-01-25T20:45:35.3341227Z ##[error]Bash exited with code ‘1’.
2022-01-25T20:45:35.3372393Z ##[section]Finishing: Run inspec tests
Hi Rajesh,
I’m good you? Thank you for the message!
I believe you are having this known error, it arrived in a new update. I raised it here in this PR, hopefully this fix it soon
https://github.com/inspec/inspec-azure/pull/605
There is a fix to change locally or possibly if you are doing self hosted agent or even if you want to try using a bash script for the fix
Thanks
Thomas
Thanks a lot for your update. Would you please share me bash script to resolve this issue via pipeline?
By the way, now i’m your supporter.Happy to be a part of your milestones.Keep going and
Hi Rajesh,
Not something I’ve actually implemented currently as we use other various tools.
If you check in that PR example, the local fix is referenced.if you map to the DevOps Pipeline
Thank you for supporting and following me on my journey 🙂
Feel free to give me a follow on Twitter/LinkedIn too!
Thanks
Thomas
Many thanks.
What do you use the templates are in another git repo from the main pipeline? Only 2 solutions I can come up with are 1) Template repo declared in the main pipeline or 2) Git submodule in the main pipeline repo.
Good article, but there is *always* a flip side…. Imagine what heppens whn 100 pipelines use the same template just to save a little it of typing…. then someone edits that one template in a way that works for their pipeline, but not the other 99…
Tradeoffs-Tradeoffs….
[Personally/Professionally I tend to go with creating higher level custom Tasks or similar. At least this way they be revisioned
Hi,
Thanks for the comment, always an interesting discussion point – templating/what to template really does depend on your team, culture & how you’ve designed initital pipelines and where they are likely to grow etc in the year/2 and beyond.
Whatever way you choose; the templating basis/fundamentals still apply
Thanks
Thomas