Skip to content

Commit 3053b5e

Browse files
committed
PipelineFailedException and PipelineCancelledException should fail fast
1 parent 5995345 commit 3053b5e

5 files changed

Lines changed: 95 additions & 22 deletions

File tree

Fun.Build.Tests/ExceptionHandlingTests.fs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,53 @@ let ``exception handling should work for parallel steps`` () =
5858

5959
Assert.True exn.IsSome
6060
Assert.Equal("/step-0> test", exn.Value.InnerException.Message)
61+
62+
[<Fact>]
63+
let ``PipelineFailedException should fail fast`` () =
64+
let mutable exn = ValueNone
65+
66+
try
67+
shouldNotBeCalled (fun call ->
68+
pipeline "" {
69+
stage "" {
70+
continueOnStepFailure
71+
run (fun _ ->
72+
raise (PipelineFailedException("demo"))
73+
()
74+
)
75+
}
76+
post [ stage "" { run call } ]
77+
runImmediate
78+
}
79+
)
80+
81+
with :? PipelineFailedException as ex ->
82+
exn <- ValueSome ex
83+
84+
Assert.True exn.IsSome
85+
Assert.Equal("demo", exn.Value.Message)
86+
87+
[<Fact>]
88+
let ``PipelineCancelledException should fail fast`` () =
89+
let mutable exn = ValueNone
90+
91+
try
92+
shouldNotBeCalled (fun call ->
93+
pipeline "" {
94+
stage "" {
95+
continueOnStepFailure
96+
run (fun _ ->
97+
raise (PipelineCancelledException("demo"))
98+
()
99+
)
100+
}
101+
post [ stage "" { run call } ]
102+
runImmediate
103+
}
104+
)
105+
106+
with :? PipelineCancelledException as ex ->
107+
exn <- ValueSome ex
108+
109+
Assert.True exn.IsSome
110+
Assert.Equal("demo", exn.Value.Message)

Fun.Build/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
## [1.1.14] - 2024-10-21
6+
7+
- PipelineFailedException and PipelineCancelledException should fail fast
8+
59
## [1.1.13] - 2024-10-21
610

711
- Improve error reporting in github actions

Fun.Build/PipelineContextExtensions.fs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -125,28 +125,36 @@ module PipelineContextExtensionsInternal =
125125
let pipelineExns = ResizeArray<exn>()
126126
use cts = new Threading.CancellationTokenSource(timeoutForPipeline)
127127

128-
AnsiConsole.MarkupLine $"[turquoise4]Run stages[/]"
129-
let hasFailedStage, stageExns = this.RunStages(this.Stages, cts.Token, failfast = true)
130-
pipelineExns.AddRange stageExns
131-
AnsiConsole.MarkupLine $"[turquoise4]Run stages finished[/]"
132-
AnsiConsole.WriteLine()
133-
AnsiConsole.WriteLine()
134128

135-
let mutable hasFailedPostStage = false
136-
if cts.IsCancellationRequested |> not then
137-
AnsiConsole.MarkupLine $"[turquoise4]Run post stages[/]"
138-
let result, postStageExns = this.RunStages(this.PostStages, cts.Token, failfast = false)
139-
hasFailedPostStage <- result
140-
pipelineExns.AddRange postStageExns
141-
AnsiConsole.MarkupLine $"[turquoise4]Run post stages finished[/]"
129+
let mutable hasErrors = false
130+
131+
try
132+
AnsiConsole.MarkupLine $"[turquoise4]Run stages[/]"
133+
let hasFailedStage, stageExns = this.RunStages(this.Stages, cts.Token, failfast = true)
134+
pipelineExns.AddRange stageExns
135+
AnsiConsole.MarkupLine $"[turquoise4]Run stages finished[/]"
142136
AnsiConsole.WriteLine()
143137
AnsiConsole.WriteLine()
144138

139+
let mutable hasFailedPostStage = false
140+
if cts.IsCancellationRequested |> not then
141+
AnsiConsole.MarkupLine $"[turquoise4]Run post stages[/]"
142+
let result, postStageExns = this.RunStages(this.PostStages, cts.Token, failfast = false)
143+
hasFailedPostStage <- result
144+
pipelineExns.AddRange postStageExns
145+
AnsiConsole.MarkupLine $"[turquoise4]Run post stages finished[/]"
146+
AnsiConsole.WriteLine()
147+
AnsiConsole.WriteLine()
148+
149+
hasErrors <- hasFailedStage || hasFailedPostStage
150+
151+
with ex ->
152+
this.PrintError ex.Message
153+
raise ex
145154

146-
let hasError = hasFailedStage || hasFailedPostStage
147155

148156
let color =
149-
if hasError then "red"
157+
if hasErrors then "red"
150158
else if cts.IsCancellationRequested then "yellow"
151159
else "lime"
152160

@@ -166,8 +174,8 @@ module PipelineContextExtensionsInternal =
166174
this.PrintError(exn.Message + " " + innerMessage)
167175
AnsiConsole.WriteLine()
168176
raise (PipelineFailedException("Pipeline is failed because of exception", pipelineExns[0]))
169-
else if hasError then
170-
AnsiConsole.MarkupLine "[red]Pipeline is failed because result is not indicating as successful[/]"
177+
else if hasErrors then
178+
this.PrintError "Pipeline is failed because result is not indicating as successful"
171179
raise (PipelineFailedException "Pipeline is failed because result is not indicating as successful")
172180

173181

Fun.Build/StageContextExtensions.fs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ module StageContextExtensionsInternal =
6262
|> fun x -> x + ctx.Name
6363

6464

65-
member ctx.PrinterError(msg: string) =
65+
member ctx.PrintError(msg: string) =
6666
match ctx.TryGetEnvVar("GITHUB_ENV") with
6767
| ValueSome _ ->
6868
let title = "[STAGE] " + ctx.GetNamePath().Replace(",", "_")
@@ -256,9 +256,9 @@ module StageContextExtensionsInternal =
256256
| Error e ->
257257
if String.IsNullOrEmpty e |> not then
258258
if not isParallel && stage.GetNoPrefixForStep() then
259-
stage.PrinterError(e)
259+
stage.PrintError(e)
260260
else
261-
stage.PrinterError(prefix + " " + e)
261+
stage.PrintError(prefix + " " + e)
262262

263263
return false
264264

@@ -289,6 +289,14 @@ module StageContextExtensionsInternal =
289289
return isSuccess, exns
290290

291291
with
292+
| :? PipelineCancelledException as ex ->
293+
raise ex
294+
return false, exns
295+
296+
| :? PipelineFailedException as ex ->
297+
raise ex
298+
return false, exns
299+
292300
| :? StepSoftCancelledException as ex ->
293301
AnsiConsole.MarkupLineInterpolated $"[yellow]{prefix} {ex.Message}.[/]"
294302
return true, exns
@@ -343,6 +351,9 @@ module StageContextExtensionsInternal =
343351
Async.RunSynchronously(ts, cancellationToken = linkedCTS.Token)
344352

345353
with
354+
| :? PipelineCancelledException as ex -> raise ex
355+
| :? PipelineFailedException as ex -> raise ex
356+
346357
| _ when isStageSoftCancelled -> isSuccess <- true
347358
| ex ->
348359
isSuccess <- false

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ If you find my projects helpful and would like to support my work, consider maki
2929
## Minimal example and conventions
3030

3131
```fsharp
32-
#r "nuget: Fun.Build, 1.1.7"
32+
#r "nuget: Fun.Build, 1.1.14"
3333
open Fun.Build
3434
3535
pipeline "demo" {
@@ -76,7 +76,7 @@ dotnet fsi build.fsx -- -p your_pipeline -h
7676
Below example covered most of the apis and usage example, take it as the documents😊:
7777

7878
```fsharp
79-
#r "nuget: Fun.Build, 1.1.7"
79+
#r "nuget: Fun.Build, 1.1.14"
8080
8181
open Fun.Result
8282
open Fun.Build

0 commit comments

Comments
 (0)