我最近一直在使用 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
我尝试过的:
我尝试过通过创建一个版本然后通过另一个 API 调用添加每个资产链接来完全避免这个问题。但由于 Gitlab 的作业令牌访问权限(该死),这种方法没有奏效。
我尝试使用单引号来捕获大部分字符串,但使用双引号转义变量替换:
ASSET_LIST=\'"${ASSET_LIST}"' --assets-link "{"name":"common_name-'"${VAR}"'.bin","url":"'"${COMMON_URL}"'/'"${VAR}"'/binary.bin"}"'\'
- 我尝试过使用
exec
:
exec release-cli create --name "Release $CI_COMMIT_TAG" --tag-name $CI_COMMIT_TAG $ASSET_LIST
- 还有其他各种小的语法变化,但它们都没有任何作用。
不幸的是,我还没有找到可行的语法/配置。
我知道变量和变量扩展有一些奇怪的怪癖,我只是想不出如何让它工作。
提前感谢您的帮助。
答案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 "$@"
轻松创建和使用命令的参数列表。