Default non-Windows bash is not invoked as documented
See original GitHub issueDescribe the bug
The documentation at https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsrun implies that when a shell is not specified on a non-Windows platform, bash (if found) will be invoked as bash --noprofile --norc -eo pipefail {0}
.
Fail-fast behavior using set -e o pipefail: Default for bash and built-in shell. It is also the default when you don’t provide an option on non-Windows platforms.
However, this is not exactly the case.
To Reproduce Steps to reproduce the behavior:
- Create an action without specifying a shell value:
- name: No shell specified (default bash)
run: echo Hello, world!
- Observe that it is executed as
shell: /bin/bash -e {0}
as per this example at https://github.com/johnstevenson/runner-actions-test/actions/runs/48283923 which also shows the documented behaviour when the shell is specified.
Expected behavior
For the command to be executed as shell: /bin/bash --noprofile --norc -e -o pipefail {0}
Runner Version and Platform
Current runner version: 2.165.2 Tested on ubuntu-latest and macos-latest
What’s not working?
Regardless of whether this is a documentation problem (or my incorrect interpretation), there is no consistency when invoking bash with and without a shell value.
The ScriptHandler:RunAsync
code (also duplicated in ScriptHandler:PrintActionDetails
) sets shellCommand
as sh
even if bash is found, resulting in the wrong format string being used:
So any fix would be:
#if OS_WINDOWS
shellCommand = "pwsh";
commandPath = WhichUtil.Which(shellCommand, require: false, Trace, prependPath);
if (string.IsNullOrEmpty(commandPath))
{
shellCommand = "powershell";
Trace.Info($"Defaulting to {shellCommand}");
commandPath = WhichUtil.Which(shellCommand, require: true, Trace, prependPath);
}
ArgUtil.NotNullOrEmpty(commandPath, "Default Shell");
#else
shellCommand = "bash";
commandPath = WhichUtil.Which(shellCommand, require: false, Trace, prependPath)
if (string.IsNullOrEmpty(commandPath))
{
shellCommand = "sh";
Trace.Info($"Defaulting to {shellCommand}");
commandPath = WhichUtil.Which(shellCommand, require: true, Trace, prependPath);
}
ArgUtil.NotNullOrEmpty(commandPath, "Default Shell");
#endif
argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat(shellCommand);
I’d happily PR this if needed and if I could find out how you debug an action in Visual Studio (are there any docs about this?)
Issue Analytics
- State:
- Created 4 years ago
- Reactions:16
- Comments:5
Top GitHub Comments
I’m aware this issue has been closed for a long time, and this does make sense for self-hosted runners and code running in the self-hosted environment.
However, for containers, wouldn’t it be preferable to query the default shell before starting the container and set the job defaults appropriately as part of container start?
eg.
Let me know if this should be a new issue/suggestion.
This is working as intended, thought I definitely understand with the docs in their current state this is very confusing.
For hosted runners, we know bash is installed, so users can expect their steps to run on it. For self hosted runners, we don’t have the same luxury.
-eo pipefail
would cause scripts executing on bash to fail where there would have passed on ash
instance, which could be confusing and tricky to debug for workflow authors who don’t have great visibility into what software is installed on the runner they landed on (or what happened to be in the PATH at the time of the run).That being said, we should update the docs to clarify this behavior. I’ve filed an issue to update the documentation so we can improve this experience.
Thank you for the report! I’m going to close out this issue for now. If you need this behavior, you can use the job defaults shell and specify it as bash to invoke all steps with
bash --noprofile --norc -eo pipefail {0}