`mypy` returning with exit status of 0 even though code is not properly type hinted in gitlab CI/CD pipeline

Presumably, the problem arises because the GitLab CI/CD pipeline executes your PowerShell code via the -Command (-c) parameter of the PowerShell CLI (powershell.exe for Windows PowerShell, pwsh for PowerShell (Core) 7+):

  • It is the last statement executed that determines the CLI invocation's exit code.

  • In your case, that translates to the calls to Get-ChildItem and ForEach-Object (%): Only if one or both calls as a whole are considered to have encountered errors - as reflected in the automatic $? variable containing $false - is 1 reported as the exit code; otherwise, it is 0.

In other words: the calls to external programs such as mypy inside the script block passed to ForEach-Object have no impact on the overall exit code.

To change that, keep track of failing external-program calls and use an explicit exit statement as the last statement (code spread across multiple lines for readability - the ; are only needed if you reformat to a single line):

$overallExitCode = 0;
(ls -recurse *.py).fullname | foreach-object { 
  echo "`n$_`n"; mypy --strict $_;
  if ($LASTEXITCODE -ne 0) { $overallExitCode = $LASTEXITCODE }
};
exit $overallExitCode

If you only care about the first failure:

(ls -recurse *.py).fullname | foreach-object { 
  echo "`n$_`n"; mypy --strict $_;
  if ($LASTEXITCODE -ne 0) { break }
};
exit $LASTEXITCODE

If you don't care about relaying the specific non-zero exit code reported by mypy and want to signal any failure with overall exit code 1, you can use the following streamlined formulation (which you've come up with yourself), which relies on the fact that a non-zero exit code reported by calls to external programs also results in $? reflecting $false:

(ls -recurse *.py).fullname | foreach-object {mypy --strict $_; if (-not $?) {exit 1}}

For more information about exit codes in PowerShell, see this answer.