Scripts in Gitlab CI/CD might contain conditions, and there are multiple options for how to solve that. But which Shell is used and which syntax should be used then? This is not documented.
🇨🇿 V češtině si lze článek přečíst na kutac.cz
If you are using a different executor than Docker, this might not be relevant for you. However, Docker executor is the default one for shared runners in gitlab.com
In gitlab-ci.yml
file you specify the Docker image and also commands to execute. You can include conditions or other constructs in those commands. But used Docker image might contain multiple Shell implementations and it is necessary to know which Shell is selected and which syntax to use.
Manually specifying Shell in *.sh
file
If the script is not written directly in .gitlab-ci.yml
file, but in an external one, you can specify the path to Shell and the path to the file. Then you don't care much which Shell is selected in the executor. The pipeline might look like this:
deploy:
image: registry.gitlab.com/pavel.kutac/docker-ftp-deployer:php81
script:
- /bin/bash /usr/local/bin/execute-deployment.sh
Condition directly inside .gitlab-ci.yml
file
You can write conditions directly into YAML with Literal block style. Then the pipeline might look like this. Used script and Docker image are taken from Parallel incremental FTP Deployer. But now you need to know, which syntax you should use.
deploy:
image: registry.gitlab.com/pavel.kutac/docker-ftp-deployer:php81
script: |
if [[ ${CI_COMMIT_MESSAGE,,} != "[skip-maintenance]"* ]]; then
wget --no-verbose -O - https://kutac.cz/some/path/to/turn/on/maintenance-mode
fi
./.ci/deploy/run-lftp-incremental-sync.sh
But how to get that info? I wasn't able to find it in the documentation. And mentioned Docker image contains Busybox sh
and also bash
. I had to dig into the source code of Gitlab runner.
And there it is clear, that Gitlab Runner first executes a short script with /bin/sh
. BashDetectShellScript
below checks different paths for different shell implementation and select one of them. The selected one is then used to execute all scripts from .gitlab-ci.yml
file.
const BashDetectShellScript = `if [ -x /usr/local/bin/bash ]; then
exec /usr/local/bin/bash $@
elif [ -x /usr/bin/bash ]; then
exec /usr/bin/bash $@
elif [ -x /bin/bash ]; then
exec /bin/bash $@
elif [ -x /usr/local/bin/sh ]; then
exec /usr/local/bin/sh $@
elif [ -x /usr/bin/sh ]; then
exec /usr/bin/sh $@
elif [ -x /bin/sh ]; then
exec /bin/sh $@
elif [ -x /busybox/sh ]; then
exec /busybox/sh $@
else
echo shell not found
exit 1
fi
`
// ...
func (b *BashShell) GetConfiguration(info common.ShellScriptInfo) (*common.ShellConfiguration, error) {
// ...
if info.Type == common.LoginShell {
script.CmdLine += " -l"
script.Arguments = []string{"-l"}
script.DockerCommand = []string{"sh", "-c", strings.ReplaceAll(BashDetectShellScript, "$@", "-l")}
} else {
script.DockerCommand = []string{"sh", "-c", strings.ReplaceAll(BashDetectShellScript, "$@", "")}
}
// ...
}
Top comments (0)