-
-
Notifications
You must be signed in to change notification settings - Fork 60
Build Failures
Build and task failures are exceptions and terminating errors. Non terminating
errors are ignored. By default all errors are terminating because the engine
sets $ErrorActionPreference = 'Stop'
before invoking build scripts.
Invoke-Build invokes build scripts and their tasks, catches errors, and mostly
re-throws them after logging and doing some extra checks for tasks (failed
tasks do not stop builds if their references are safe (job Task -Safe)
).
If a build is invoked with the switch Safe
then the engine stores an error as
the property Error
of the result object and returns quietly. Exceptions are
still possible, they are not build failures but fatal errors like invalid
arguments, missing build scripts, and etc.
There are several ways to cause failures with more or less important differences in errors.
Use assert
(Assert-Build
) in order to check for a condition and fail with
the default or a custom message if a condition is not evaluated to true.
task Example {
assert (...) "Something is wrong."
}
Error messages from assert
and equals
are distinctive, they emphasize
failures caused by unexpected conditions. Error information points to the line
of code where assert
or equals
fails.
Consider to use equals X Y
instead of assert (X -eq Y)
. It is easier to
type, it avoids subtle PowerShell conversions, and its error message shows
object values and types.
Use standard PowerShell throw
in order to throw an error from task code
task Example {
throw "Something is wrong."
}
Error source information points to the code line where an error is thrown.
Do not use Write-Error
in tasks. It works but error source information is not
useful, it points to some engine code that calls a task, not the error source.
On the other hand, Write-Error
can be useful in a function shared between
tasks if such errors should point to a task which calls a function and causes
its failure.
If Invoke-Build is called from PowerShell and a caller is about to process
failures then try..catch
should be used.
try {
Invoke-Build ...
}
catch {
# build failed, $_ is the error
}
Alternatively, invoke a build with the switch Safe
and the parameter Result
and then check the result property Error
.
Invoke-Build -Safe -Result Result ...
if ($Result.Error) {
# build failed, $Result.Error is the error
}
else {
# build succeeded
}
If none of the above is used then at least consider to set
$ErrorActionPreference = 'Stop'
before calling Invoke-Build from a script with some other commands after it. Otherwise, on some build failures script may just write errors and continue.
If Invoke-Build is called by other applications with PowerShell.exe then a caller analyses the exit code. It is 0 if a build succeeds. Other exit codes are for failures.
PowerShell.exe -NoProfile -Command "Invoke-Build ..."
if ERRORLEVEL 1 goto fail
echo Build succeeded.
exit /b 0
:fail
echo Build FAILED.
exit /b %ERRORLEVEL%
One use case is invoking Invoke-Build from MSBuild using the task Exec. Nothing special is needed for failure detection, this task fails when Invoke-Build fails (due to not zero exit code).
<Exec Command='PowerShell.exe -NoProfile "Invoke-Build ..."'/>
Another MSBuild use case is PostBuildEvent in Visual Studio projects (their are also MSBuild scripts). Nothing special is needed for failure detection, too. The post build event fails if Invoke-Build fails.
<PropertyGroup>
<PostBuildEvent>PowerShell.exe -NoProfile "Invoke-Build ..."</PostBuildEvent>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
</PropertyGroup>
- Concepts
- Script Tutorial
- Incremental Tasks
- Partial Incremental Tasks
- How Build Works
- Special Variables
- Build Failures
- Build Analysis
- Parallel Builds
- Persistent Builds
- Portable Build Scripts
- Using for Test Automation
- Debugging Tips
- VSCode Tips
Helpers
- Invoke Task from VSCode
- Generate VSCode Tasks
- Invoke Task from ISE
- Resolve MSBuild
- Show Build Trees
- Show Build Graph
- Argument Completers
- Invoke-Build.template
Appendix