2017-10-19 144 views
1

我们最近搬到了Gitlab并开始使用管线。我们建立了一个构建服务器(Ubuntu 16.04实例)并安装了一个使用Shell执行程序的运行程序,但我不确定它是如何实际执行.gitlab-ci.yml文件中定义的脚本的。考虑下面的代码片段:Shell执行程序如何运行脚本?

script: 
    - sh authenticate.sh $DEPLOY_KEY 
    - cd MAIN && sh deploy.sh && cd .. 
    - sh deploy_service.sh MATCHMAKING 
    - sh deauthenticate.sh 

我的印象是,它只是管这些命令猛砸,因此我期待默认猛砸行为。但是,发生的情况是deploy.shssh错误而失败;然后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错误)?任何见解将不胜感激。

+2

“SH deploy.sh”你调用'sh'这里不是'bash'。它们在您的系统上可能不是同一件事。如果你想bash,调用bash。 – Kenster

+0

@Kenster'bash'用于在该脚本上调用'sh',并使用适当的退出代码(第一个错误为127,第二个错误为255)将错误返回给'bash'。问题是'bash'没有按照预期检测到错误。 – Amposter

+0

来自文档:#如果构建应该在另一个用户(shell执行程序)的上下文中执行,则使用此命令 'cat generated-bash-script | su --shell/bin/bash --login user' – Amposter

回答

0

Gitlab脚本块实际上是一个shell脚本数组。 https://docs.gitlab.com/ee/ci/yaml/#script 数组中每个元素的失败都会失败整个数组。 要解决把你的脚本块在一些script.sh文件

script: 
    - ./script.sh 
0

我不认为你的sh deploy.sh正在产生一个非零退出代码。

如果命令以非零返回码退出,但您正在创建运行shell脚本的子进程,您正在使用set -e来告诉当前进程退出。

这里的,我已经叫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家当:

#!/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 

要解决你的问题,我相信你需要:使用./deploy.sh

  • 添加-e到脚本家当线(#!/bin/bash -e
  • 调用脚本的bash直接,而不是运行通过脚本sh

记住,如果deploy.sh确实失败则cd ..运行(&&方式运行下一个命令,如果前面的一个成功),这意味着你是在错误的目录运行deploy_service.sh。你会用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脚本,没有庆典,因此所有的这一轮可能会更好:

script: 
    - ./authenticate.sh $DEPLOY_KEY 
    - (cd MAIN && ./deploy.sh) 
    - ./deploy_service.sh MATCHMAKING 
    - ./deauthenticate.sh 
+0

'deploy.sh'返回一个非零的退出代码(我在脚本中使用'set -e',并且多次检查'$?'变量)。我知道'&&'警告以及为什么下一个声明失败,但这是不言而喻的。重点是两行('cd MAIN && sh deploy.sh && cd ..'和'sh deploy_service。sh MATCHMAKING')正在返回非零退出代码,但执行程序仅在第二个语句失败时发生错误。 – Amposter