作为命令参数的 JSON 字符串列表

作为命令参数的 JSON 字符串列表

我最近一直在使用 GitLab CI 来自动执行一些繁忙的任务,即自动发布版本标签的二进制文件。

对于那些不了解 Gitlab CI 的人来说,它非常简单。它拉取指定的 docker 镜像并在该 docker 容器的默认 shell 中运行“脚本”命令。

Gitlab 提供的发布 CLI docker 镜像仅包含基本组件,这意味着没有 bash,只有 sh(或类似的东西,我不太清楚是什么)

我原本有这个:(为方便阅读,删除了额外的作业配置)

Release:
  image: registry.gitlab.com/gitlab-org/release-cli:latest
  script:
    - |
      release-cli create --name "Release $CI_COMMIT_TAG" --tag-name $CI_COMMIT_TAG \
        --assets-link "{\"name\":\"${FILE_A_NAME}\",\"url\":\"${COMMON_URL}/${SPECIFIC_PART_A}\"}" \
        --assets-link "{\"name\":\"${FILE_B_NAME}\",\"url\":\"${COMMON_URL}/${SPECIFIC_PART_B}\"}" \
        --assets-link "{\"name\":\"${FILE_C_NAME}\",\"url\":\"${COMMON_URL}/${SPECIFIC_PART_C}\"}" \
        --assets-link "{\"name\":\"${FILE_D_NAME}\",\"url\":\"${COMMON_URL}/${SPECIFIC_PART_D}\"}" \

我正在尝试制作一个 CI 模板,以减少在多个项目之间复制该模板的次数,从而允许它们始终使用最新的 CI 配置。这可以在 gitlab 中使用include:yaml 部分完成。

但是,我在创建参数字符串以附加到命令末尾时遇到了问题。这是我目前所拥有的:

variables: # Example BUILD_ENVS
  BUILD_ENVS: "env_A env_B env_C"

Release:
  image: registry.gitlab.com/gitlab-org/release-cli:latest
  script:
    - |
      ASSET_LIST=""
      for ENV in ${BUILD_ENVS}
      do
          ASSET_LIST="${ASSET_LIST} --assets-link \"{\\\"name\\\":\\\"common_name-${VAR}.bin\\\",\\\"url\\\":\\\"${COMMON_URL}/${VAR}/binary.bin\\\"}\""
      done
    - release-cli create --name "Release $CI_COMMIT_TAG" --tag-name $CI_COMMIT_TAG $ASSET_LIST

当我回显该ASSET_LIST变量时,我得到了正确的字符串。(都输出预期的字符串

echo $ASSET_STRING
echo "$ASSET_STRING"

release-cli ... $ASSET_LIST失败并出现以下错误:

$ release-cli create --name "Release $CI_COMMIT_TAG" --tag-name $CI_COMMIT_TAG $ASSET_LIST

time="2021-04-24T23:36:04Z" level=info msg="Creating Release..." cli=release-cli command=create name="Release v1.2.3" project-id=25750732 ref=3b5c58a057fd4ae781e7ce9e695dd8e5d88ffbf6 server-url="https://gitlab.com" tag-name=v1.2.3 version=0.7.0

time="2021-04-24T23:36:04Z" level=fatal msg="new CreateReleaseRequest: failed to parse assets: invalid JSON: \"\\\"{\\\\\\\"name\\\\\\\":\\\\\\\"File-A-binery.bin\\\\\\\",\\\\\\\"url\\\\\\\":\\\\\\\"https://url-to-file-A/binary.bin\\\\\\\"}\\\"\"" cli=release-cli version=0.7.0

我尝试过的:

  1. 我尝试过通过创建一个版本然后通过另一个 API 调用添加每个资产链接来完全避免这个问题。但由于 Gitlab 的作业令牌访问权限(该死),这种方法没有奏效。

  2. 我尝试使用单引号来捕获大部分字符串,但使用双引号转义变量替换:

ASSET_LIST=\'"${ASSET_LIST}"' --assets-link "{"name":"common_name-'"${VAR}"'.bin","url":"'"${COMMON_URL}"'/'"${VAR}"'/binary.bin"}"'\'
  1. 我尝试过使用exec
exec release-cli create --name "Release $CI_COMMIT_TAG" --tag-name $CI_COMMIT_TAG $ASSET_LIST
  1. 还有其他各种小的语法变化,但它们都没有任何作用。

不幸的是,我还没有找到可行的语法/配置。

我知道变量和变量扩展有一些奇怪的怪癖,我只是想不出如何让它工作。

提前感谢您的帮助。

答案1

我找到了一个解决方案。这可能不是最好的方法。但它确实有效。

@ilkkachu 的回答完全符合我的需要 我们如何运行存储在变量中的命令

他列出了许多方法,但对我有用的是使用$@位置参数的方法来。

这是我所做的:

variables: # Example BUILD_ENVS
  BUILD_ENVS: "env_A env_B env_C"

Release:
  image: registry.gitlab.com/gitlab-org/release-cli:latest
  script:
    - |
      for ENV in ${BUILD_ENVS}
      do
          set -- "$@" --assets-link "{\"name\":\"common_name-${VAR}.bin\",\"url\":\"${COMMON_URL}/${VAR}/binary.bin\"}"
      done
    - release-cli create --name "Release $CI_COMMIT_TAG" --tag-name $CI_COMMIT_TAG "$@"

虽然 docker 镜像使用的普通 shell 不支持数组,但它确实具有用于脚本的位置参数数组。由于我们运行的不是脚本,而是命令列表,因此我们不使用位置参数,我们可以覆盖该对象并自己使用它。

有关其工作原理的更多信息,请参阅@ilkkachu 更长/更好的答案

TLDR:如果您不担心脚本或命令中的位置参数,请使用set -- "$@" -arguement "{\"json\":\"part\"}"command "$@"轻松创建和使用命令的参数列表。

相关内容