Add feature flag to disable delayed expansion

For Windows Batch we are using !errorlevel! insteadf of %errorlevel%
this means that the errorlevel value is expanded when it's executed not
when it's read.

More detail on how this works check https://devblogs.microsoft.com/oldnewthing/20060823-00/?p=29993
parent c1ec30ab
......@@ -30,5 +30,7 @@ change hidden behind the feature flag disabled a corresponding environment varia
|--------------------------------------|---------------|------------|--------------------|-------------|
| `FF_K8S_USE_ENTRYPOINT_OVER_COMMAND` | `true` | ✓ | 12.0 | Enables [the fix][mr-1010] for entrypoint configuration when `kubernetes` executor is used. |
| `FF_DOCKER_HELPER_IMAGE_V2` | `false` | ✓ | 12.0 | Enable the helper image to use the new commands when [helper_image](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnersdocker-section) is specified. This will start using the new API that will be used in 12.0 and stop showing the warning message in the build log. |
| `FF_CMD_DISABLE_DELAYED_ERROR_LEVEL_EXPANSION` | `false` | ✓ | TBA | Disables [EnableDelayedExpansion](https://ss64.com/nt/delayedexpansion.html) for error checking for when using [Window Batch](https://docs.gitlab.com/runner/shells/#windows-batch) shell. |
[mr-1010]: https://gitlab.com/gitlab-org/gitlab-runner/merge_requests/1010
......@@ -20,8 +20,9 @@ type CmdShell struct {
type CmdWriter struct {
bytes.Buffer
TemporaryPath string
indent int
TemporaryPath string
indent int
disableDelayedErrorLevelExpansion bool
}
func batchQuote(text string) string {
......@@ -80,10 +81,19 @@ func (b *CmdWriter) Unindent() {
}
func (b *CmdWriter) checkErrorLevel() {
b.Line("IF !errorlevel! NEQ 0 exit /b !errorlevel!")
errCheck := "IF !errorlevel! NEQ 0 exit /b !errorlevel!"
b.Line(b.updateErrLevelCheck(errCheck))
b.Line("")
}
func (b *CmdWriter) updateErrLevelCheck(errCheck string) string {
if b.disableDelayedErrorLevelExpansion {
return strings.Replace(errCheck, "!", "%", -1)
}
return errCheck
}
func (b *CmdWriter) Command(command string, arguments ...string) {
b.Line(b.buildCommand(command, arguments...))
b.checkErrorLevel()
......@@ -134,14 +144,16 @@ func (b *CmdWriter) IfFile(path string) {
func (b *CmdWriter) IfCmd(cmd string, arguments ...string) {
cmdline := b.buildCommand(cmd, arguments...)
b.Line(fmt.Sprintf("%s 2>NUL 1>NUL", cmdline))
b.Line("IF !errorlevel! EQU 0 (")
errCheck := "IF !errorlevel! EQU 0 ("
b.Line(b.updateErrLevelCheck(errCheck))
b.Indent()
}
func (b *CmdWriter) IfCmdWithOutput(cmd string, arguments ...string) {
cmdline := b.buildCommand(cmd, arguments...)
b.Line(fmt.Sprintf("%s", cmdline))
b.Line("IF !errorlevel! EQU 0 (")
errCheck := "IF !errorlevel! EQU 0 ("
b.Line(b.updateErrLevelCheck(errCheck))
b.Indent()
}
......@@ -243,7 +255,8 @@ func (b *CmdShell) GetConfiguration(info common.ShellScriptInfo) (script *common
func (b *CmdShell) GenerateScript(buildStage common.BuildStage, info common.ShellScriptInfo) (script string, err error) {
w := &CmdWriter{
TemporaryPath: info.Build.FullProjectDir() + ".tmp",
TemporaryPath: info.Build.FullProjectDir() + ".tmp",
disableDelayedErrorLevelExpansion: info.Build.IsFeatureFlagOn("FF_CMD_DISABLE_DELAYED_ERROR_LEVEL_EXPANSION"),
}
if buildStage == common.BuildStagePrepare {
......
......@@ -2,6 +2,7 @@ package shells
import (
"fmt"
"strconv"
"testing"
"github.com/stretchr/testify/assert"
......@@ -68,3 +69,22 @@ func TestCMD_IfCmdShellEscapes(t *testing.T) {
assert.Equal(t, "\"foo\" \"x^&(y)\" 2>NUL 1>NUL\r\nIF !errorlevel! EQU 0 (\r\n", writer.String())
}
func TestCMD_DelayedExpanstionFeatureFlag(t *testing.T) {
cases := map[bool]string{
true: "\"foo\"\r\nIF %errorlevel% NEQ 0 exit /b %errorlevel%\r\n\r\n",
false: "\"foo\"\r\nIF !errorlevel! NEQ 0 exit /b !errorlevel!\r\n\r\n",
}
for disableDelayedErrorLevelExpansion, expectedCmd := range cases {
t.Run("disableDelayedErrorLevelExpansion_"+strconv.FormatBool(disableDelayedErrorLevelExpansion), func(t *testing.T) {
writer := &CmdWriter{
disableDelayedErrorLevelExpansion: disableDelayedErrorLevelExpansion,
}
writer.Command("foo")
assert.Equal(t, expectedCmd, writer.String())
})
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment