[英]How does the Shell executor run scripts?
我们最近搬到了Gitlab,并开始使用管道。 我们已经设置了一个构建服务器(一个Ubuntu 16.04实例),并安装了一个使用Shell执行程序的运行程序,但是我不确定它如何实际执行.gitlab-ci.yml
文件中定义的脚本。 考虑以下代码片段:
script:
- sh authenticate.sh $DEPLOY_KEY
- cd MAIN && sh deploy.sh && cd ..
- sh deploy_service.sh MATCHMAKING
- sh deauthenticate.sh
我的印象是它将这些命令通过管道传递给Bash,因此我期待默认的Bash行为。 但是,由于ssh
错误,导致deploy.sh
失败了; Bash然后继续执行deploy_service.sh
(这是预期的行为),但是由于无法can't open deploy_service.sh
错误而失败,并且作业在没有Bash执行最后一条语句的情况下终止。
据我了解,如果您先执行set -e
,Bash只会在出错时中止,因此我期望所有语句都将被执行。 我尝试将set -e
作为第一条语句添加,但这没有任何区别-它不会在第一个ssh
错误时终止。
我在下面添加了来自Gitlab的确切输出:
没有set -e
$ cd MAIN && sh deploy.sh && cd ..
deploy.sh: 72: deploy.sh: Bad substitution
Building JS bundles locally...
> better-npm-run build
running better-npm-run in x
Executing script: build
to be executed: node ./bin/build
-> building js bundle...
-> minifying js bundle...
Uploading JS bundles to server temp folder...
COMMENCING RESTART. 5,4,3,2,1...
ssh: Could not resolve hostname $: Name or service not known
$ sh deploy_service.sh MATCHMAKING
sh: 0: Can't open deploy_service.sh
ERROR: Job failed: exit status 1
带有set -e
$ set -e
$ cd MAIN && sh deploy.sh && cd ..
deploy.sh: 72: deploy.sh: Bad substitution
Building JS bundles locally...
> better-npm-run build
running better-npm-run in x
Executing script: build
to be executed: node ./bin/build
-> building js bundle...
-> minifying js bundle...
Uploading JS bundles to server temp folder...
COMMENCING RESTART. 5,4,3,2,1...
ssh: Could not resolve hostname $: Name or service not known
$ sh deploy_service.sh MATCHMAKING
sh: 0: Can't open deploy_service.sh
ERROR: Job failed: exit status 1
为什么在没有set -e
情况下以错误终止(也为什么仅在第二个错误而不是ssh
错误终止)? 任何见解将不胜感激。
Gitlab脚本块实际上是外壳脚本的数组。 https://docs.gitlab.com/ee/ci/yaml/#script数组中每个元素的失败将使整个数组失败。 要解决此问题,请将您的脚本块放在一些script.sh文件中
喜欢
script:
- ./script.sh
我认为您的sh deploy.sh
不会生成非零的退出代码。
您正在使用set -e
告诉当前进程退出(如果命令以非零返回码退出),但是您正在创建一个子进程来运行Shell脚本。
这是我称为deploy.sh
的简单示例脚本:
#!/bin/bash
echo "First."
echox "Error"
echo "Second"
如果我运行脚本,则可以看到错误的处理方式:
$ sh deploy.sh
First.
deploy.sh: line 5: echox: command not found
Second
如果我先运行set -e
,您将看不到它的作用。
$ set -e
$ sh deploy.sh
First.
deploy.sh: line 5: echox: command not found
Second
现在,我将-e
添加到/bin/bash
shebang中:
#!/bin/bash -e
echo "First."
echox "Error"
echo "Second"
当我使用sh
运行脚本时, -e
仍然无效。
$ sh ./deploy.sh
First.
./deploy.sh: line 3: echox: command not found
Second
使用bash直接运行此脚本时, -e
生效。
$ ./deploy.sh
First.
./deploy.sh: line 3: echox: command not found
要解决您的问题,我相信您需要:
-e
添加到脚本shebang行( #!/bin/bash -e
) ./deploy.sh
直接从bash调用脚本,而不通过sh
运行脚本。 请记住,如果deploy.sh
确实失败,则cd ..
将不会运行( &&
表示如果前一个命令成功,则运行下一个命令),这意味着您位于错误的目录中,无法运行deploy_service.sh
。 使用cd MAIN; sh deploy.sh; cd ..
会更好cd MAIN; sh deploy.sh; cd ..
cd MAIN; sh deploy.sh; cd ..
cd MAIN; sh deploy.sh; cd ..
,但是我建议用更简单的替代方法替换对deploy.sh
的调用:
script:
- sh authenticate.sh $DEPLOY_KEY
- (cd MAIN && sh deploy.sh)
- sh deploy_service.sh MATCHMAKING
- sh deauthenticate.sh
这没有什么大不相同,但是将导致cd MAIN && sh deploy.sh
在子进程中运行(括号是这样做的),这意味着整个脚本的当前目录不受影响。 可以将其想象为“生成一个子流程,并在子流程的更改目录中并运行该脚本”,并且当该子流程完成时,您将在开始的地方结束。
正如其他用户所评论的那样,您实际上是在sh而不是bash中运行脚本,因此全面来看可能会更好:
script:
- ./authenticate.sh $DEPLOY_KEY
- (cd MAIN && ./deploy.sh)
- ./deploy_service.sh MATCHMAKING
- ./deauthenticate.sh
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.