Powershell runner ignores ParserErrors
When using windows runner in docker
If your build script contains commands with PowerShell operators like if or while and you put a mistake in the command line. PowerShell will print out the error, but return True
Steps to reproduce
- create a job for windows runner with the following script in
.gitlab-ci.yml
.gitlab-ci.yml
script:
- New-Item -ItemType Directory -Force -Path build
- Set-Location -Path build
- if ($TEST_VAR) { () }
- echo "WE DID NOT FAIL"
Actual behavior
PS C:\docker> if ($TEST_VAR) { () }
At line:1 char:19
+ if ($TEST_VAR) { () }
+ ~
An expression was expected after '('.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ExpectedExpression
PS C:\docker> echo $?
True
And Job succeed.
Expected behavior
Expected job failure after ParserError.
Relevant logs and/or screenshots
job log
PS C:\builds\project1> echo "`$ New-Item -ItemType Directory -Force -Path build"
$ New-Item -ItemType Directory -Force -Path build
PS C:\builds\project1> New-Item -ItemType Directory -Force -Path build
Directory: C:\builds\project1
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 1/23/2020 12:45 AM build
PS C:\builds\project1> if(!$?) { Exit &{if($LASTEXITCODE) {$LASTEXITCODE} else {1}} }
PS C:\builds\project1>
PS C:\builds\project1> echo "`$ Set-Location -Path build"
$ Set-Location -Path build
PS C:\builds\project1> Set-Location -Path build
PS C:\builds\project1\build> if(!$?) { Exit &{if($LASTEXITCODE) {$LASTEXITCODE} else {1}} }
PS C:\builds\project1\build>
PS C:\builds\project1\build> echo "`$ if ($TEST_VAR) { () }"
$ if ($TEST_VAR) { () }
PS C:\builds\project1\build> if ($TEST_VAR) { () }
At line:1 char:19
+ if ($TEST_VAR) { () }
+ ~
An expression was expected after '('.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ExpectedExpression
PS C:\builds\project1\build> if(!$?) { Exit &{if($LASTEXITCODE) {$LASTEXITCODE} else {1}} }
PS C:\builds\project1\build>
PS C:\builds\project1\build> echo "`$ echo `"WE DID NOT FAIL`""
$ echo "WE DID NOT FAIL"
PS C:\builds\project1\build> echo "WE DID NOT FAIL"
WE DID NOT FAIL
Environment description
We are using Runners with executor docker-windows on windows server 2019 with native containers
config.toml contents
concurrent = 1
check_interval = 0
[session_server]
session_timeout = 1800
[[runners]]
name = "Docker-WIN-XXXXXYYYZZZ-2"
url = "https://gitlab.domain.tld/"
token = "XXXXXXXXXXXXXXXXXXXX"
executor = "docker-windows"
shell = "powershell"
[runners.custom_build_dir]
[runners.docker]
tls_verify = false
image = "mcr.microsoft.com/windows/servercore:ltsc2019"
cpus = "8.0"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["c:\\cache"]
shm_size = 0
[runners.cache]
Used GitLab Runner version
Running with gitlab-runner 12.6.0 (ac8e767a)
on Docker-WIN-XXXXXYYYZZZ-2 Hz34LWND
Using Docker executor with image windows:2019.12.26 ...
Possible fixes
We have found the solution to catch ParserError by using $Error
- $Error – collection (ArrayList to be specific) of errors that have occurred in the current session. Errors are always inserted at the beginning of the collection. As a result, the most recent error is always located at index 0.
Possible fix is to https://gitlab.com/gitlab-org/gitlab-runner/blob/master/shells/powershell.go#L71
func (b *PsWriter) checkErrorLevel() {
b.Line("if(!$?) { Exit &{if($LASTEXITCODE) {$LASTEXITCODE} else {1}} }")
b.Line("")
b.Line("if($Error.Count -ne 0) { Echo $Error; Exit 1 }")
b.Line("")
}