Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

The linter is writing warnings to the standard error stream rather than the standard warning stream. #13995

Closed
VanessaRussell opened this issue May 2, 2024 · 3 comments
Assignees
Labels
documentation Improvements or additions to documentation Needs: Triage 🔍

Comments

@VanessaRussell
Copy link

Bicep version
Bicep CLI version 0.26.170 (e9abaf1)

Describe the bug
The linter is writing warnings to the standard error stream rather than the standard warning stream.
It's possible that the issue is limited to only this rule:
Warning no-loc-expr-outside-params: Use a parameter here instead of 'resourceGroup().location'. 'resourceGroup().location' and 'deployment().location' should only be used as a default value for parameters. [https://aka.ms/bicep/linter/no-loc-expr-outside-params]

To Reproduce
Steps to reproduce the behavior:

  1. Write a bicep file that will trigger the above linter warning
  2. Build it via az bicep build
  3. Observe that it is writing to the Error Stream rather than the Warning Stream

Additional context
Add any other context about the problem here.
I have an ADO Pipeline that attempts to build a set of bicep files and verify that it is successful before allowing PRs to be merged. I updated the task to failOnStderr: true as the build sometimes passed even though the az bicep build command created errors. Now my pipeline is failing because of the above linting warning writing to Error Stream.

Example Pipeline Task:

- task: PowerShell@2
  displayName: Build Bicep Files
  inputs:
    failOnStderr: true
    filePath: $(buildBicepScriptPath)
    pwsh: true
    arguments: -SearchPaths $(searchPaths)

Example Powershell Script:

param(
    [Parameter(Mandatory = $true)]
    [string[]]
    $SearchPaths
)

az bicep version

Write-Host `n'Building bicep files...'

foreach ($searchPath in $SearchPaths) {
    Write-Host `n'Looking for resource files in:' $searchPath`n

    $filesToBuild = Get-ChildItem Resources.bicep -Path $searchPath -Recurse -File

    if ($filesToBuild.Length -eq 0) {
        Write-Host 'Did not find any Resources.bicep files.' -ForegroundColor Red
    }
    
    foreach ($file in $filesToBuild) {
        Write-Host 'Building:' $file.FullName
        az bicep build --file $file.FullName
    }
}

Write-Host `n'Finished building bicep files.'

Example Bicep File with warning:

@description('Additional app settings to be added to the web app')
param additionalAppSettings object = {}

@description('Resource name for the Azure App Config instance this function uses')
param appConfigName string

@description('The Azure App Config labels this app should pull in')
param appConfigLabelFilters string

@description('The key that Azure App Config should watch to trigger its refresh')
param appConfigRefreshSentinelKey string = 'RefreshSentinel'

@description('The label in which the Refresh Sentinel key is stored')
param appConfigRefreshSentinelLabel string

@description('Which app insights resource should telemetry be sent to?')
param appInsightsName string

@description('Denotes the desired name for the app service plan')
param appServicePlanName string

@description('What sku to use for the app service plan?')
param appServicePlanSku string

@description('Resource name for the Azure Key Vault instance this app uses')
param keyVaultName string

@description('Desired set of tags to apply to each created resource')
param resourceTags object = {}

@description('Which location should resources be deployed to?')
param targetLocation string = resourceGroup().location 

// Internal variable Location parameter to overwrite when target location not defined in variable group
var targetLocationToDeploy = targetLocation == '' ?  resourceGroup().location : targetLocation

@description('Denotes the desired name for the web app')
param webAppName string

@description('Denotes the desired slot name for the web app')
param webAppSlotName string

@description('Denotes the desired time zone for the web app')
param webAppTimeZone string = 'Pacific Standard Time'

@description('Denotes the desired .net version for the web app')
param netFrameworkVersion string = 'v6.0'

resource appServicePlan 'Microsoft.Web/serverfarms@2021-03-01' = {
  name: appServicePlanName
  location: targetLocationToDeploy
  sku: {
    name: appServicePlanSku
  }
  properties: {
    // Workaround for https://github.com/Azure/bicep/issues/7865
  }
  tags: resourceTags
}

resource appInsights 'Microsoft.Insights/components@2020-02-02' existing = {
  name: appInsightsName
}

resource appConfig 'Microsoft.AppConfiguration/configurationStores@2020-06-01' existing = {
  name: appConfigName
}

var defaultAppSettings = {
  'AppConfigSettings:Endpoint': appConfig.properties.endpoint
  'AppConfigSettings:UnparsedLabelFilters': appConfigLabelFilters
  'AppConfigSettings:RefreshSentinelKey': appConfigRefreshSentinelKey
  'AppConfigSettings:RefreshSentinelLabel': appConfigRefreshSentinelLabel
  APPLICATIONINSIGHTS_CONNECTION_STRING: appInsights.properties.ConnectionString
  WEBSITE_TIME_ZONE: webAppTimeZone
}

var webAppProperties = {
  clientAffinityEnabled: false
  httpsOnly: true
  serverFarmId: appServicePlan.id
  siteConfig: {
    alwaysOn: true
    ftpsState: 'Disabled'
    use32BitWorkerProcess: false
    webSocketsEnabled: false
    netFrameworkVersion: netFrameworkVersion
  }
}

resource webApp 'Microsoft.Web/sites@2021-03-01' = {
  name: webAppName
  location: targetLocationToDeploy
  kind: 'webapp'
  identity: {
    type: 'SystemAssigned'
  }
  properties: webAppProperties
  tags: resourceTags
}

Example Pipeline Log:
image

@stephaniezyen stephaniezyen self-assigned this May 8, 2024
@stephaniezyen stephaniezyen added the documentation Improvements or additions to documentation label May 8, 2024
@mortenlerudjordet
Copy link

As a workaround add a bicepconfig file to the repo or in a root folder on the agent with:
"no-loc-expr-outside-params": {
"level": "off"
}

https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-config-linter

@anthony-c-martin
Copy link
Member

anthony-c-martin commented May 29, 2024

Please note that "standard warning" is a purely powershell concept - there's no actual standard warning stream that a CLI application can use, so az and bicep CLIs have no choice but to use stderr for diagnostics.

The exit code will tell you precisely whether a particular command has failed - personally I would recommend trying to use this instead to determine success. Here's how I would solve it personally - with the below you could then avoid using the failOnStderr property, because the non-zero exit code will indicate failure.

param(
    [Parameter(Mandatory = $true)]
    [string[]]
    $SearchPaths
)

$hasErrors = $false
function ExecSafe([scriptblock] $ScriptBlock) {
    & $ScriptBlock
    if ($LASTEXITCODE -ne 0) {
        Write-Error "Failed to execute command: $ScriptBlock"
        $hasErrors = $true
    }
}

ExecSafe { az bicep version }

Write-Host `n'Building bicep files...'

foreach ($searchPath in $SearchPaths) {
    Write-Host `n'Looking for resource files in:' $searchPath`n

    $filesToBuild = Get-ChildItem Resources.bicep -Path $searchPath -Recurse -File

    if ($filesToBuild.Length -eq 0) {
        Write-Host 'Did not find any Resources.bicep files.' -ForegroundColor Red
    }
    
    foreach ($file in $filesToBuild) {
        Write-Host 'Building:' $file.FullName
        ExecSafe { az bicep build --file $file.FullName }
    }
}

Write-Host `n'Finished building bicep files.'

if ($hasErrors) {
    exit 1
}

@VanessaRussell
Copy link
Author

@mortenlerudjordet - Yes, but this then turns the warning off everywhere and not just in the one single permitted place. We still want the warning to happen elsewhere.

@anthony-c-martin - Thanks for the additional info. I wasn't aware that powershell's "standard warning" was not a wrapper around an existing cmd one.

I attempted to use your suggested code; however, I ran into the following error:
image

That said, the real "meat" of the suggestion was to have the script to return a non-zero exit code when $LASTEXITCODE is not 0. This seems to be working as expected without the need of the failOnStderr task param.

Since there is no "standard warning" at the cmd level and the root of my issue has been resolved via your suggestion, I've gone ahead and chosen to close this issue. Thank you 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation Needs: Triage 🔍
Projects
Status: Done
Development

No branches or pull requests

4 participants