diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 4d88e0f..8758b7a 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,10 +3,11 @@ "isRoot": true, "tools": { "fantomas": { - "version": "5.2.1", + "version": "8.0.0-beta-002", "commands": [ "fantomas" - ] + ], + "rollForward": false } } } \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index 1f7ae51..f511c15 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,8 +9,10 @@ fsharp_max_record_width=60 fsharp_max_array_or_list_width=120 fsharp_max_value_binding_width=120 fsharp_max_function_binding_width=120 -fsharp_max_dot_get_expression_width=120 -fsharp_multiline_block_brackets_on_same_column=true +fsharp_multiline_bracket_style=stroustrup +fsharp_newline_before_multiline_computation_expression=false fsharp_multi_line_lambda_closing_newline=true fsharp_blank_lines_around_nested_multiline_expressions=false -fsharp_experimental_stroustrup_style=true \ No newline at end of file + +[*.fsx] +fsharp_newline_before_multiline_computation_expression=true diff --git a/.github/workflows/Build and publish nuget package.yml b/.github/workflows/Build and publish nuget package.yml index 25fc4ed..1c5f539 100644 --- a/.github/workflows/Build and publish nuget package.yml +++ b/.github/workflows/Build and publish nuget package.yml @@ -14,12 +14,14 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v7 - name: Setup .NET Core - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@v6 with: - dotnet-version: 8.0.x + dotnet-version: | + 8.0.x + 10.0.x - name: Use build.fsx env: diff --git a/.github/workflows/Run tests for PR.yml b/.github/workflows/Run tests for PR.yml index fdbe8bf..4b3b8ed 100644 --- a/.github/workflows/Run tests for PR.yml +++ b/.github/workflows/Run tests for PR.yml @@ -10,12 +10,14 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v7 - name: Setup .NET Core - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@v6 with: - dotnet-version: 8.0.x + dotnet-version: | + 8.0.x + 10.0.x - name: Use build.fsx run: dotnet fsi ./build.fsx -- -p test diff --git a/Fun.Build.Cli/History.fs b/Fun.Build.Cli/History.fs index 898e7e8..5f66187 100644 --- a/Fun.Build.Cli/History.fs +++ b/Fun.Build.Cli/History.fs @@ -101,67 +101,66 @@ type History = ?withLastArgs: bool, ?promptForContinuation: bool, ?continuationItems: Collections.Generic.List - ) = - asyncResult { - let withLastArgs = defaultArg withLastArgs false - let scriptFile = Path.GetFileName history.Pipeline.Script - let scriptDir = Path.GetDirectoryName history.Pipeline.Script - let promptForContinuation = defaultArg promptForContinuation false - - let table = Table() - table.ShowHeaders <- false - table.AddColumns("", "") |> ignore - table.AddRow("Script", $"[green]{scriptFile}[/]") |> ignore - table.AddRow("Pipeline", $"[bold green]{history.Pipeline.Name}[/]") |> ignore - table.AddRow("WorkingDir", $"[green]{scriptDir}[/]") |> ignore - table.AddRow("Arguments", history.Args) |> ignore - - AnsiConsole.Write table - AnsiConsole.MarkupLine("New arguments (leave empty to use the one from history):") - - let args = - if withLastArgs then - history.Args - else - let text = TextPrompt("> ") - text.AllowEmpty <- true - let newArgs = AnsiConsole.Prompt text - if String.IsNullOrEmpty newArgs then history.Args else newArgs - + ) = asyncResult { + let withLastArgs = defaultArg withLastArgs false + let scriptFile = Path.GetFileName history.Pipeline.Script + let scriptDir = Path.GetDirectoryName history.Pipeline.Script + let promptForContinuation = defaultArg promptForContinuation false + + let table = Table() + table.ShowHeaders <- false + table.AddColumns("", "") |> ignore + table.AddRow("Script", $"[green]{scriptFile}[/]") |> ignore + table.AddRow("Pipeline", $"[bold green]{history.Pipeline.Name}[/]") |> ignore + table.AddRow("WorkingDir", $"[green]{scriptDir}[/]") |> ignore + table.AddRow("Arguments", history.Args) |> ignore + + AnsiConsole.Write table + AnsiConsole.MarkupLine("New arguments (leave empty to use the one from history):") + + let args = + if withLastArgs then + history.Args + else + let text = TextPrompt("> ") + text.AllowEmpty <- true + let newArgs = AnsiConsole.Prompt text + if String.IsNullOrEmpty newArgs then history.Args else newArgs + + AnsiConsole.MarkupLine("") + + let currentItems = continuationItems |> Option.defaultWith (fun () -> Collections.Generic.List()) + currentItems.Add({ history with Args = args }) + + if promptForContinuation && not withLastArgs then + if AnsiConsole.Confirm("Do you want to select another history to continue?", defaultValue = false) then + match History.PromptSelect() with + | ValueSome item -> do! History.Run(ctx, item, continuationItems = currentItems, promptForContinuation = true) + | _ -> () AnsiConsole.MarkupLine("") - let currentItems = continuationItems |> Option.defaultWith (fun () -> Collections.Generic.List()) - currentItems.Add({ history with Args = args }) - - if promptForContinuation && not withLastArgs then - if AnsiConsole.Confirm("Do you want to select another history to continue?", defaultValue = false) then - match History.PromptSelect() with - | ValueSome item -> do! History.Run(ctx, item, continuationItems = currentItems, promptForContinuation = true) - | _ -> () - AnsiConsole.MarkupLine("") - - // If there is no continuation commands need to fill, then we consider it should be executed now - if continuationItems.IsNone then - for index, history in Seq.indexed currentItems do - let scriptFile = Path.GetFileName history.Pipeline.Script - let scriptDir = Path.GetDirectoryName history.Pipeline.Script - let isHelpCommand = history.Args.Trim().ToLower() = "-h" - - if not isHelpCommand then - History.Add { history with StartedTime = DateTime.Now } - - if index = 0 then - AnsiConsole.Console.MarkupLine("[green]Start executing...[/]") - else - AnsiConsole.Console.MarkupLine("[green]Continue executing...[/]") - AnsiConsole.Console.WriteLine() - - try - do! - ctx.RunCommand($"dotnet fsi \"{scriptFile}\" -- -p {history.Pipeline.Name} {history.Args}", workingDir = scriptDir) - |> Async.map (ignore >> Ok) - with _ -> - () - - if currentItems.Count = 1 && isHelpCommand then do! History.Run(ctx, history) - } + // If there is no continuation commands need to fill, then we consider it should be executed now + if continuationItems.IsNone then + for index, history in Seq.indexed currentItems do + let scriptFile = Path.GetFileName history.Pipeline.Script + let scriptDir = Path.GetDirectoryName history.Pipeline.Script + let isHelpCommand = history.Args.Trim().ToLower() = "-h" + + if not isHelpCommand then + History.Add { history with StartedTime = DateTime.Now } + + if index = 0 then + AnsiConsole.Console.MarkupLine("[green]Start executing...[/]") + else + AnsiConsole.Console.MarkupLine("[green]Continue executing...[/]") + AnsiConsole.Console.WriteLine() + + try + do! + ctx.RunCommand($"dotnet fsi \"{scriptFile}\" -- -p {history.Pipeline.Name} {history.Args}", workingDir = scriptDir) + |> Async.map (ignore >> Ok) + with _ -> + () + + if currentItems.Count = 1 && isHelpCommand then do! History.Run(ctx, history) + } diff --git a/Fun.Build.Cli/Pipeline.fs b/Fun.Build.Cli/Pipeline.fs index 0071aef..bebdcff 100644 --- a/Fun.Build.Cli/Pipeline.fs +++ b/Fun.Build.Cli/Pipeline.fs @@ -157,68 +157,66 @@ type Pipeline with pipeline: Pipeline, ?promptForContinuation: bool, ?continuationCommands: Collections.Generic.List<{| Pipeline: Pipeline; Args: string |}> - ) = - asyncResult { - let promtForContinuation = defaultArg promptForContinuation false - let scriptFile = Path.GetFileName pipeline.Script - let scriptDir = Path.GetDirectoryName pipeline.Script + ) = asyncResult { + let promtForContinuation = defaultArg promptForContinuation false + let scriptFile = Path.GetFileName pipeline.Script + let scriptDir = Path.GetDirectoryName pipeline.Script - let table = Table() - table.ShowHeaders <- false - table.AddColumns("", "") |> ignore - table.AddRow("Script", $"[green]{scriptFile}[/]") |> ignore - table.AddRow("Pipeline", $"[bold green]{pipeline.Name}[/]") |> ignore - table.AddRow("WorkingDir", $"[green]{scriptDir}[/]") |> ignore - if String.IsNullOrEmpty(pipeline.Description.Trim()) |> not then - table.AddRow("Description", $"[green]{pipeline.Description}[/]") |> ignore + let table = Table() + table.ShowHeaders <- false + table.AddColumns("", "") |> ignore + table.AddRow("Script", $"[green]{scriptFile}[/]") |> ignore + table.AddRow("Pipeline", $"[bold green]{pipeline.Name}[/]") |> ignore + table.AddRow("WorkingDir", $"[green]{scriptDir}[/]") |> ignore + if String.IsNullOrEmpty(pipeline.Description.Trim()) |> not then + table.AddRow("Description", $"[green]{pipeline.Description}[/]") |> ignore - AnsiConsole.Write table + AnsiConsole.Write table - let textPrompt = TextPrompt("Arguments (-h for help): ") - textPrompt.AllowEmpty <- true - let args = AnsiConsole.Prompt textPrompt + let textPrompt = TextPrompt("Arguments (-h for help): ") + textPrompt.AllowEmpty <- true + let args = AnsiConsole.Prompt textPrompt - let currentCommands = continuationCommands |> Option.defaultWith (fun () -> Collections.Generic.List()) - currentCommands.Add({| Pipeline = pipeline; Args = args |}) + let currentCommands = continuationCommands |> Option.defaultWith (fun () -> Collections.Generic.List()) + currentCommands.Add({| Pipeline = pipeline; Args = args |}) + AnsiConsole.MarkupLine("") + + if promtForContinuation then + if AnsiConsole.Confirm("Do you want to select another pipeline to continue?", defaultValue = false) then + match Pipeline.PromptSelect() with + | ValueSome item -> do! Pipeline.Run(ctx, item, continuationCommands = currentCommands, promptForContinuation = true) + | _ -> () AnsiConsole.MarkupLine("") - if promtForContinuation then - if AnsiConsole.Confirm("Do you want to select another pipeline to continue?", defaultValue = false) then - match Pipeline.PromptSelect() with - | ValueSome item -> do! Pipeline.Run(ctx, item, continuationCommands = currentCommands, promptForContinuation = true) - | _ -> () - AnsiConsole.MarkupLine("") - - if continuationCommands.IsNone then - for index, command in Seq.indexed currentCommands do - let scriptFile = Path.GetFileName command.Pipeline.Script - let scriptDir = Path.GetDirectoryName command.Pipeline.Script - let isHelpCommand = command.Args.Trim().ToLower() = "-h" - - if not isHelpCommand then - History.Add - { - Pipeline = pipeline - Args = args - StartedTime = DateTime.Now - } - - if index = 0 then - AnsiConsole.Console.MarkupLine("[green]Start executing...[/]") - else - AnsiConsole.Console.MarkupLine("[green]Continue executing...[/]") - AnsiConsole.Console.WriteLine() - - try - do! - ctx.RunCommand($"dotnet fsi \"{scriptFile}\" -- -p {command.Pipeline.Name} {command.Args}", workingDir = scriptDir) - |> Async.map (ignore >> Ok) - with _ -> - () - - if isHelpCommand && currentCommands.Count = 1 then - do! Pipeline.Run(ctx, pipeline) - } + if continuationCommands.IsNone then + for index, command in Seq.indexed currentCommands do + let scriptFile = Path.GetFileName command.Pipeline.Script + let scriptDir = Path.GetDirectoryName command.Pipeline.Script + let isHelpCommand = command.Args.Trim().ToLower() = "-h" + + if not isHelpCommand then + History.Add { + Pipeline = pipeline + Args = args + StartedTime = DateTime.Now + } + + if index = 0 then + AnsiConsole.Console.MarkupLine("[green]Start executing...[/]") + else + AnsiConsole.Console.MarkupLine("[green]Continue executing...[/]") + AnsiConsole.Console.WriteLine() + + try + do! + ctx.RunCommand($"dotnet fsi \"{scriptFile}\" -- -p {command.Pipeline.Name} {command.Args}", workingDir = scriptDir) + |> Async.map (ignore >> Ok) + with _ -> + () + + if isHelpCommand && currentCommands.Count = 1 then + do! Pipeline.Run(ctx, pipeline) + } diff --git a/Fun.Build.Tests/ConditionsBuilderTests.fs b/Fun.Build.Tests/ConditionsBuilderTests.fs index 4aa2eae..b7b6135 100644 --- a/Fun.Build.Tests/ConditionsBuilderTests.fs +++ b/Fun.Build.Tests/ConditionsBuilderTests.fs @@ -9,386 +9,320 @@ open Fun.Build.PipelineContextExtensionsInternal [] let ``whenCmd should work`` () = - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - whenCmd { name "test1" } - run call - } - runImmediate - } - ) - - shouldBeCalled (fun call -> - pipeline "" { - cmdArgs [ "test1" ] - stage "" { - whenCmd { name "test1" } - run call - } - runImmediate - } - ) - - shouldBeCalled (fun call -> - pipeline "" { - cmdArgs [ "test1"; "v1" ] - stage "" { + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + whenCmd { name "test1" } + run call + } + runImmediate + }) + + shouldBeCalled (fun call -> pipeline "" { + cmdArgs [ "test1" ] + stage "" { + whenCmd { name "test1" } + run call + } + runImmediate + }) + + shouldBeCalled (fun call -> pipeline "" { + cmdArgs [ "test1"; "v1" ] + stage "" { + whenCmd { + name "test1" + acceptValues [ "v1"; "v2" ] + } + run call + } + runImmediate + }) + + shouldBeCalled (fun call -> pipeline "" { + cmdArgs [ "-t"; "v1" ] + stage "" { + whenAll { whenCmd { name "test1" + alias "-t" acceptValues [ "v1"; "v2" ] } - run call - } - runImmediate - } - ) - - shouldBeCalled (fun call -> - pipeline "" { - cmdArgs [ "-t"; "v1" ] - stage "" { - whenAll { - whenCmd { - name "test1" - alias "-t" - acceptValues [ "v1"; "v2" ] - } - } - run call } - runImmediate + run call } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - stage "" { - whenCmd { - name "test1" - optional - } - run call + shouldBeCalled (fun call -> pipeline "" { + stage "" { + whenCmd { + name "test1" + optional } - runImmediate + run call } - ) + runImmediate + }) [] let ``whenCmdArg should work`` () = - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - whenCmdArg "test1" - run call - } - runImmediate + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + whenCmdArg "test1" + run call } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - cmdArgs [ "test1" ] - stage "" { - whenCmdArg "test1" - run call - } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + cmdArgs [ "test1" ] + stage "" { + whenCmdArg "test1" + run call } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - stage "" { - whenCmdArg "test1" "value" "description" true - run call - } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + stage "" { + whenCmdArg "test1" "value" "description" true + run call } - ) + runImmediate + }) - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - whenCmdArg "test1" "value" "description" false - run call - } - runImmediate + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + whenCmdArg "test1" "value" "description" false + run call } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - cmdArgs [ "test1"; "value" ] - stage "" { - whenCmdArg "test1" "value" "description" false - run call - } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + cmdArgs [ "test1"; "value" ] + stage "" { + whenCmdArg "test1" "value" "description" false + run call } - ) + runImmediate + }) [] let ``whenEnv should work`` () = - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - whenEnv { name "test1" } - run call - } - runImmediate - } - ) - - shouldBeCalled (fun call -> - pipeline "" { - envVars [ "test1", "" ] - stage "" { - whenEnv { name "test1" } - run call - } - runImmediate - } - ) - - shouldBeCalled (fun call -> - pipeline "" { - envVars [ "test1", "v1" ] - stage "" { + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + whenEnv { name "test1" } + run call + } + runImmediate + }) + + shouldBeCalled (fun call -> pipeline "" { + envVars [ "test1", "" ] + stage "" { + whenEnv { name "test1" } + run call + } + runImmediate + }) + + shouldBeCalled (fun call -> pipeline "" { + envVars [ "test1", "v1" ] + stage "" { + whenEnv { + name "test1" + acceptValues [ "v1"; "v2" ] + } + run call + } + runImmediate + }) + + shouldBeCalled (fun call -> pipeline "" { + envVars [ "test1", "v1" ] + stage "" { + whenAll { whenEnv { name "test1" acceptValues [ "v1"; "v2" ] } - run call - } - runImmediate - } - ) - - shouldBeCalled (fun call -> - pipeline "" { - envVars [ "test1", "v1" ] - stage "" { - whenAll { - whenEnv { - name "test1" - acceptValues [ "v1"; "v2" ] - } - } - run call } - runImmediate + run call } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - stage "" { - whenEnv { - name "test1" - optional - } - run call + shouldBeCalled (fun call -> pipeline "" { + stage "" { + whenEnv { + name "test1" + optional } - runImmediate + run call } - ) + runImmediate + }) [] let ``whenEnvVar should work`` () = - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - whenEnvVar "test1" - run call - } - runImmediate + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + whenEnvVar "test1" + run call } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - envVars [ "test1", "" ] - stage "" { - whenEnvVar "test1" - run call - } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + envVars [ "test1", "" ] + stage "" { + whenEnvVar "test1" + run call } - ) + runImmediate + }) [] let ``when' stage should use stage execution result as when' condition for stage`` () = - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - when' (stage "" { run (fun ctx -> 1) }) - run call - } - runImmediate + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + when' (stage "" { run (fun ctx -> 1) }) + run call } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - stage "" { - when' (stage "" { run (fun ctx -> 0) }) - run call - } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + stage "" { + when' (stage "" { run (fun ctx -> 0) }) + run call } - ) + runImmediate + }) - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - whenStage "" { run (fun _ -> 1) } - run call - } - runImmediate + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + whenStage "" { run (fun _ -> 1) } + run call } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - stage "" { - whenStage "" { run (fun _ -> 0) } - run call - } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + stage "" { + whenStage "" { run (fun _ -> 0) } + run call } - ) + runImmediate + }) [] let ``when' stage should have parent context in execution mode`` () = - shouldBeCalled (fun call -> - pipeline "" { - envVars [ "ENV", "0" ] - stage "" { - when' (stage "" { run (fun ctx -> ctx.GetEnvVar("ENV") |> int) }) - run call - } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + envVars [ "ENV", "0" ] + stage "" { + when' (stage "" { run (fun ctx -> ctx.GetEnvVar("ENV") |> int) }) + run call } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - envVars [ "ENV", "0" ] - stage "" { - whenStage "" { run (fun ctx -> ctx.GetEnvVar("ENV") |> int) } - run call - } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + envVars [ "ENV", "0" ] + stage "" { + whenStage "" { run (fun ctx -> ctx.GetEnvVar("ENV") |> int) } + run call } - ) + runImmediate + }) [] let ``when' stage should use stage execution result as when' condition for nested stage`` () = - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - stage "nested" { - when' (stage "" { run (fun ctx -> 1) }) - run call - } + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + stage "nested" { + when' (stage "" { run (fun ctx -> 1) }) + run call } - runImmediate } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - stage "" { - stage "nested" { - when' (stage "" { run (fun ctx -> 0) }) - run call - } + shouldBeCalled (fun call -> pipeline "" { + stage "" { + stage "nested" { + when' (stage "" { run (fun ctx -> 0) }) + run call } - runImmediate } - ) + runImmediate + }) [] let ``when' stage should use stage execution result as when' condition in composed when`` () = - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - whenAll { when' (stage "" { run (fun ctx -> 1) }) } - run call - } - runImmediate + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + whenAll { when' (stage "" { run (fun ctx -> 1) }) } + run call } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - stage "" { - whenAll { when' (stage "" { run (fun ctx -> 0) }) } - run call - } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + stage "" { + whenAll { when' (stage "" { run (fun ctx -> 0) }) } + run call } - ) + runImmediate + }) - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - whenAll { whenStage "" { run (fun _ -> 1) } } - run call - } - runImmediate + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + whenAll { whenStage "" { run (fun _ -> 1) } } + run call } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - stage "" { - whenAll { whenStage "" { run (fun _ -> 0) } } - run call - } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + stage "" { + whenAll { whenStage "" { run (fun _ -> 0) } } + run call } - ) + runImmediate + }) [] let ``when' stage should work in pipeline directly`` () = - Assert.Throws(fun _ -> - pipeline "" { - when' (stage "" { run (fun _ -> 1) }) - runImmediate - } - ) + Assert.Throws(fun _ -> pipeline "" { + when' (stage "" { run (fun _ -> 1) }) + runImmediate + }) |> ignore - shouldBeCalled (fun call -> - pipeline "" { - when' (stage "" { run (fun _ -> 0) }) - stage "" { run call } - runImmediate - } - ) + shouldBeCalled (fun call -> pipeline "" { + when' (stage "" { run (fun _ -> 0) }) + stage "" { run call } + runImmediate + }) - Assert.Throws(fun _ -> - pipeline "" { - whenStage "" { run (fun _ -> 1) } - runImmediate - } - ) + Assert.Throws(fun _ -> pipeline "" { + whenStage "" { run (fun _ -> 1) } + runImmediate + }) |> ignore - shouldBeCalled (fun call -> - pipeline "" { - whenStage "" { run (fun _ -> 0) } - stage "" { run call } - runImmediate - } - ) + shouldBeCalled (fun call -> pipeline "" { + whenStage "" { run (fun _ -> 0) } + stage "" { run call } + runImmediate + }) [] let ``whenAny should work`` () = @@ -399,20 +333,23 @@ let ``whenAny should work`` () = let pipeline = PipelineContext.Create "" - { StageContext.Create "" with - ParentContext = pipeline |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = pipeline |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.False - { StageContext.Create "" with - ParentContext = { pipeline with CmdArgs = [ "test1" ] } |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = { pipeline with CmdArgs = [ "test1" ] } |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.True - { StageContext.Create "" with - ParentContext = { pipeline with EnvVars = Map.ofList [ "test2", "" ] } |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = { pipeline with EnvVars = Map.ofList [ "test2", "" ] } |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.True @@ -429,15 +366,17 @@ let ``whenAny should work`` () = } // All commands are optional, so it should return true when no command is provided - { StageContext.Create "" with - ParentContext = pipeline |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = pipeline |> StageParent.Pipeline |> ValueSome } |> condition2.Invoke |> Assert.True // All commands are optional, so it should return true if one command is provided - { StageContext.Create "" with - ParentContext = { pipeline with CmdArgs = [ "test1"; "v1" ] } |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = { pipeline with CmdArgs = [ "test1"; "v1" ] } |> StageParent.Pipeline |> ValueSome } |> condition2.Invoke |> Assert.True @@ -454,15 +393,17 @@ let ``whenAny should work`` () = } // Because at least one command is optional it should return true when no command is provided - { StageContext.Create "" with - ParentContext = pipeline |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = pipeline |> StageParent.Pipeline |> ValueSome } |> condition3.Invoke |> Assert.True // It should return true if a non-optional command is provided - { StageContext.Create "" with - ParentContext = { pipeline with CmdArgs = [ "test1" ] } |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = { pipeline with CmdArgs = [ "test1" ] } |> StageParent.Pipeline |> ValueSome } |> condition3.Invoke |> Assert.True @@ -479,32 +420,37 @@ let ``whenAll should work`` () = let pipeline = PipelineContext.Create "" - { StageContext.Create "" with - ParentContext = pipeline |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = pipeline |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.False - { StageContext.Create "" with - ParentContext = { pipeline with CmdArgs = [ "test1" ] } |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = { pipeline with CmdArgs = [ "test1" ] } |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.False - { StageContext.Create "" with - ParentContext = { pipeline with EnvVars = Map.ofList [ "test2", "" ] } |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = { pipeline with EnvVars = Map.ofList [ "test2", "" ] } |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.False - { StageContext.Create "" with - ParentContext = - { pipeline with - CmdArgs = [ "test1" ] - EnvVars = Map.ofList [ "test2", "" ] - } - |> StageParent.Pipeline - |> ValueSome + { + StageContext.Create "" with + ParentContext = + { + pipeline with + CmdArgs = [ "test1" ] + EnvVars = Map.ofList [ "test2", "" ] + } + |> StageParent.Pipeline + |> ValueSome } |> condition.Invoke |> Assert.True @@ -519,32 +465,37 @@ let ``whenNot should work`` () = let pipeline = PipelineContext.Create "" - { StageContext.Create "" with - ParentContext = pipeline |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = pipeline |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.True - { StageContext.Create "" with - ParentContext = { pipeline with CmdArgs = [ "test1" ] } |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = { pipeline with CmdArgs = [ "test1" ] } |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.False - { StageContext.Create "" with - ParentContext = { pipeline with EnvVars = Map.ofList [ "test2", "" ] } |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = { pipeline with EnvVars = Map.ofList [ "test2", "" ] } |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.False - { StageContext.Create "" with - ParentContext = - { pipeline with - CmdArgs = [ "test1" ] - EnvVars = Map.ofList [ "test2", "" ] - } - |> StageParent.Pipeline - |> ValueSome + { + StageContext.Create "" with + ParentContext = + { + pipeline with + CmdArgs = [ "test1" ] + EnvVars = Map.ofList [ "test2", "" ] + } + |> StageParent.Pipeline + |> ValueSome } |> condition.Invoke |> Assert.False @@ -567,26 +518,30 @@ let ``when compose should work`` () = let pipeline = PipelineContext.Create "" - { StageContext.Create "" with - ParentContext = pipeline |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = pipeline |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.False - { StageContext.Create "" with - ParentContext = { pipeline with CmdArgs = [ "test1" ] } |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = { pipeline with CmdArgs = [ "test1" ] } |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.True - { StageContext.Create "" with - ParentContext = { pipeline with CmdArgs = [ "test2" ] } |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = { pipeline with CmdArgs = [ "test2" ] } |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.True - { StageContext.Create "" with - ParentContext = { pipeline with CmdArgs = [ "test3" ] } |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = { pipeline with CmdArgs = [ "test3" ] } |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.False @@ -626,8 +581,9 @@ let ``condition builder should follow the sequence`` () = ) } - { StageContext.Create "" with - ParentContext = PipelineContext.Create "" |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = PipelineContext.Create "" |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.False @@ -660,8 +616,9 @@ let ``condition builder should follow the sequence`` () = ) } - { StageContext.Create "" with - ParentContext = PipelineContext.Create "" |> StageParent.Pipeline |> ValueSome + { + StageContext.Create "" with + ParentContext = PipelineContext.Create "" |> StageParent.Pipeline |> ValueSome } |> condition.Invoke |> Assert.False @@ -671,42 +628,38 @@ let ``condition builder should follow the sequence`` () = [] let ``for top level condition of stage or pipeline it should combine all condition with && rule`` () = - shouldBeCalled (fun call -> - pipeline "" { - cmdArgs [ "-t" ] - envVars [ "ENV", "" ] + shouldBeCalled (fun call -> pipeline "" { + cmdArgs [ "-t" ] + envVars [ "ENV", "" ] + + when' true + whenCmdArg "-t" + whenEnvVar "ENV" + stage "" { when' true whenCmdArg "-t" whenEnvVar "ENV" - stage "" { - when' true - whenCmdArg "-t" - whenEnvVar "ENV" + run (fun _ -> call ()) + } - run (fun _ -> call ()) - } + runImmediate + }) - runImmediate - } - ) + shouldNotBeCalled (fun call -> pipeline "" { + cmdArgs [ "-t" ] - shouldNotBeCalled (fun call -> - pipeline "" { - cmdArgs [ "-t" ] + when' true + whenCmdArg "-t" + stage "" { when' true whenCmdArg "-t" + whenEnvVar "ENV" - stage "" { - when' true - whenCmdArg "-t" - whenEnvVar "ENV" - - run (fun _ -> call ()) - } - - runImmediate + run (fun _ -> call ()) } - ) + + runImmediate + }) diff --git a/Fun.Build.Tests/ExceptionHandlingTests.fs b/Fun.Build.Tests/ExceptionHandlingTests.fs index 5139db9..2b66c97 100644 --- a/Fun.Build.Tests/ExceptionHandlingTests.fs +++ b/Fun.Build.Tests/ExceptionHandlingTests.fs @@ -9,18 +9,16 @@ let ``exception handling should work for sync steps`` () = let mutable exn = ValueNone try - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - run (fun _ -> - failwith "test" - () - ) - run call - } - runImmediate + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + run (fun _ -> + failwith "test" + () + ) + run call } - ) + runImmediate + }) with :? PipelineFailedException as ex -> exn <- ValueSome ex @@ -33,25 +31,23 @@ let ``exception handling should work for parallel steps`` () = let mutable exn = ValueNone try - shouldNotBeCalled (fun call -> - pipeline "" { + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + paralle + run (fun _ -> async { + do! Async.Sleep 10 + failwith "test" + () + }) stage "" { - paralle run (fun _ -> async { - do! Async.Sleep 10 - failwith "test" - () + do! Async.Sleep 100 + call () }) - stage "" { - run (fun _ -> async { - do! Async.Sleep 100 - call () - }) - } } - runImmediate } - ) + runImmediate + }) with :? PipelineFailedException as ex -> exn <- ValueSome ex @@ -64,19 +60,17 @@ let ``PipelineFailedException should fail fast`` () = let mutable exn = ValueNone try - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - continueOnStepFailure - run (fun _ -> - raise (PipelineFailedException("demo")) - () - ) - } - post [ stage "" { run call } ] - runImmediate + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + continueOnStepFailure + run (fun _ -> + raise (PipelineFailedException("demo")) + () + ) } - ) + post [ stage "" { run call } ] + runImmediate + }) with :? PipelineFailedException as ex -> exn <- ValueSome ex @@ -89,19 +83,17 @@ let ``PipelineCancelledException should fail fast`` () = let mutable exn = ValueNone try - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - continueOnStepFailure - run (fun _ -> - raise (PipelineCancelledException("demo")) - () - ) - } - post [ stage "" { run call } ] - runImmediate + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + continueOnStepFailure + run (fun _ -> + raise (PipelineCancelledException("demo")) + () + ) } - ) + post [ stage "" { run call } ] + runImmediate + }) with :? PipelineCancelledException as ex -> exn <- ValueSome ex diff --git a/Fun.Build.Tests/PipelineBuilderTests.fs b/Fun.Build.Tests/PipelineBuilderTests.fs index 914b832..54e5b73 100644 --- a/Fun.Build.Tests/PipelineBuilderTests.fs +++ b/Fun.Build.Tests/PipelineBuilderTests.fs @@ -8,133 +8,113 @@ open System.Threading.Tasks [] let ``pipeline should world with multiple stages with different conditions`` () = - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - whenCmdArg "test1" - run call - } - stage "" { - whenEnvVar "test2" - run call - } - runImmediate + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + whenCmdArg "test1" + run call } - ) + stage "" { + whenEnvVar "test2" + run call + } + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - cmdArgs [ "test1" ] - stage "" { - whenCmdArg "test1" - run call - } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + cmdArgs [ "test1" ] + stage "" { + whenCmdArg "test1" + run call } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - envVars [ "test2", "" ] - stage "" { - whenEnvVar "test2" - run call - } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + envVars [ "test2", "" ] + stage "" { + whenEnvVar "test2" + run call } - ) + runImmediate + }) - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - whenAll { - cmdArg "test1" - envVar "test2" - } - run call + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + whenAll { + cmdArg "test1" + envVar "test2" } - runImmediate + run call } - ) + runImmediate + }) - shouldNotBeCalled (fun call -> - pipeline "" { - cmdArgs [ "test1" ] - stage "" { - whenAll { - cmdArg "test1" - envVar "test2" - } - run call + shouldNotBeCalled (fun call -> pipeline "" { + cmdArgs [ "test1" ] + stage "" { + whenAll { + cmdArg "test1" + envVar "test2" } - runImmediate + run call } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - cmdArgs [ "test1" ] - envVars [ "test2", "" ] - stage "" { - timeout 1000 - whenAll { - cmdArg "test1" - envVar "test2" - } - timeout 1000 - run call + shouldBeCalled (fun call -> pipeline "" { + cmdArgs [ "test1" ] + envVars [ "test2", "" ] + stage "" { + timeout 1000 + whenAll { + cmdArg "test1" + envVar "test2" } - runImmediate + timeout 1000 + run call } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - stage "" { run call } - runImmediate - } - ) + shouldBeCalled (fun call -> pipeline "" { + stage "" { run call } + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - stage "" { run ignore } - stage "" { run call } - stage "" { - paralle - run "dotnet --version" - run "dotnet --list-sdks" - } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + stage "" { run ignore } + stage "" { run call } + stage "" { + paralle + run "dotnet --version" + run "dotnet --list-sdks" } - ) + runImmediate + }) [] let ``post stage should always run when other stage is failed`` () = Assert.Throws(fun _ -> - shouldBeCalled (fun call -> - pipeline "" { - stage "" { - run (fun _ -> - failwith "test" - () - ) - } - post [ stage "" { run call } ] - runImmediate + shouldBeCalled (fun call -> pipeline "" { + stage "" { + run (fun _ -> + failwith "test" + () + ) } - ) + post [ stage "" { run call } ] + runImmediate + }) ) |> ignore Assert.Throws(fun _ -> - shouldBeCalled (fun call -> - pipeline "" { - stage "" { run (fun _ -> -1) } - post [ stage "" { run call } ] - runImmediate - } - ) + shouldBeCalled (fun call -> pipeline "" { + stage "" { run (fun _ -> -1) } + post [ stage "" { run call } ] + runImmediate + }) ) |> ignore @@ -143,58 +123,48 @@ let ``post stage should always run when other stage is failed`` () = [] let ``all post stages should always run when some post stages are failed`` () = Assert.Throws(fun _ -> - shouldBeCalled (fun call -> - pipeline "" { - post [ - stage "" { - run (fun _ -> - failwith "test" - () - ) - } - stage "" { run call } - ] - runImmediate - } - ) + shouldBeCalled (fun call -> pipeline "" { + post [ + stage "" { + run (fun _ -> + failwith "test" + () + ) + } + stage "" { run call } + ] + runImmediate + }) ) |> ignore Assert.Throws(fun _ -> - shouldBeCalled (fun call -> - pipeline "" { - post [ stage "" { run (fun _ -> -1) }; stage "" { run call } ] - runImmediate - } - ) + shouldBeCalled (fun call -> pipeline "" { + post [ stage "" { run (fun _ -> -1) }; stage "" { run call } ] + runImmediate + }) ) |> ignore [] let ``runIfOnlySpecified should work`` () = - shouldBeCalled (fun call -> - pipeline "demo" { - cmdArgs [ "-p"; "demo" ] - stage "" { run call } - runIfOnlySpecified - } - ) + shouldBeCalled (fun call -> pipeline "demo" { + cmdArgs [ "-p"; "demo" ] + stage "" { run call } + runIfOnlySpecified + }) - shouldNotBeCalled (fun call -> - pipeline "demo" { - stage "" { run call } - runIfOnlySpecified - } - ) + shouldNotBeCalled (fun call -> pipeline "demo" { + stage "" { run call } + runIfOnlySpecified + }) - shouldBeCalled (fun call -> - pipeline "demo" { - timeout 1 - stage "" { run call } - runIfOnlySpecified false - } - ) + shouldBeCalled (fun call -> pipeline "demo" { + timeout 1 + stage "" { run call } + runIfOnlySpecified false + }) [] let ``runIfOnlySpecified should work for multiple -p`` () = @@ -239,7 +209,11 @@ let ``parallel should work`` () = } runImmediate } - Assert.InRange(sw.ElapsedMilliseconds, 1000, 2000) + // Upper bounds are deliberately loose: these are wall-clock assertions and CI runners + // are shared and slow. What each bound encodes: + // parallel - must stay well under the 3000ms the sequential version needs + // sequential - must be at least 2500ms, which is what proves it did not run in parallel + Assert.InRange(sw.ElapsedMilliseconds, 1000, 2400) sw.Restart() pipeline "" { @@ -251,7 +225,7 @@ let ``parallel should work`` () = runImmediate } let elapsed = sw.ElapsedMilliseconds - Assert.InRange(elapsed, 2500, 4000) + Assert.InRange(elapsed, 2500, 10000) [] @@ -324,167 +298,141 @@ let ``Syntax check`` () = [] let ``Verification should work`` () = Assert.Throws(fun _ -> - shouldNotBeCalled (fun call -> - pipeline "" { - whenCmdArg "123" - stage "" { run call } - post [ stage "" { run call } ] - runImmediate - } - ) + shouldNotBeCalled (fun call -> pipeline "" { + whenCmdArg "123" + stage "" { run call } + post [ stage "" { run call } ] + runImmediate + }) ) |> ignore Assert.Throws(fun _ -> - shouldNotBeCalled (fun call -> - pipeline "" { - verify (fun _ -> false) - stage "" { run call } - post [ stage "" { run call } ] - runImmediate - } - ) - ) - |> ignore - - shouldBeCalled (fun call -> - pipeline "" { - cmdArgs [ "123" ] - whenAll { cmdArg "123" } + shouldNotBeCalled (fun call -> pipeline "" { + verify (fun _ -> false) stage "" { run call } post [ stage "" { run call } ] runImmediate - } + }) ) + |> ignore + + shouldBeCalled (fun call -> pipeline "" { + cmdArgs [ "123" ] + whenAll { cmdArg "123" } + stage "" { run call } + post [ stage "" { run call } ] + runImmediate + }) [] let ``when' stage should use stage execution result as verification condition for pipeline`` () = let mutable numChecks = 0 Assert.Throws(fun _ -> - shouldNotBeCalled (fun call -> - pipeline "" { - when' ( - stage "whenStageShouldFail" { - run (fun ctx -> - numChecks <- numChecks + 1 - 1 - ) - } - ) - stage "" { run call } - runImmediate - } - ) + shouldNotBeCalled (fun call -> pipeline "" { + when' ( + stage "whenStageShouldFail" { + run (fun ctx -> + numChecks <- numChecks + 1 + 1 + ) + } + ) + stage "" { run call } + runImmediate + }) ) |> ignore Assert.Equal(1, numChecks) - shouldBeCalled (fun call -> - pipeline "" { - when' (stage "whenStageShouldPass" { run (fun ctx -> 0) }) - stage "" { run call } - runImmediate - } - ) + shouldBeCalled (fun call -> pipeline "" { + when' (stage "whenStageShouldPass" { run (fun ctx -> 0) }) + stage "" { run call } + runImmediate + }) [] let ``Should fail if stage is ignored`` () = Assert.Throws(fun _ -> - shouldNotBeCalled (fun call -> - pipeline "" { - stage "" { - whenCmdArg "123" - failIfIgnored - run call - } - runImmediate + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { + whenCmdArg "123" + failIfIgnored + run call } - ) + runImmediate + }) ) |> ignore Assert.Throws(fun _ -> - shouldNotBeCalled (fun call -> - pipeline "" { + shouldNotBeCalled (fun call -> pipeline "" { + stage "" { stage "" { - stage "" { - whenCmdArg "123" - failIfIgnored - run call - } - } - runImmediate - } - ) - ) - |> ignore - - shouldBeCalled (fun call -> - pipeline "1" { - cmdArgs [ "123" ] - stage "2" { - stage "3" { whenCmdArg "123" failIfIgnored run call } } runImmediate - } + }) ) + |> ignore + + shouldBeCalled (fun call -> pipeline "1" { + cmdArgs [ "123" ] + stage "2" { + stage "3" { + whenCmdArg "123" + failIfIgnored + run call + } + } + runImmediate + }) [] let ``whenCmdArg should work`` () = Assert.Throws(fun _ -> - shouldNotBeCalled (fun call -> - pipeline "" { - whenCmdArg "test1" - stage "" { run call } - runImmediate - } - ) - ) - |> ignore - - shouldBeCalled (fun call -> - pipeline "" { - cmdArgs [ "test1" ] + shouldNotBeCalled (fun call -> pipeline "" { whenCmdArg "test1" stage "" { run call } runImmediate - } + }) ) + |> ignore - shouldBeCalled (fun call -> - pipeline "" { - whenCmdArg "test1" "value" "description" true - stage "" { run call } - runImmediate - } - ) + shouldBeCalled (fun call -> pipeline "" { + cmdArgs [ "test1" ] + whenCmdArg "test1" + stage "" { run call } + runImmediate + }) - Assert.Throws(fun _ -> - shouldNotBeCalled (fun call -> - pipeline "" { - whenCmdArg "test1" "value" "description" false - stage "" { run call } - runImmediate - } - ) - ) - |> ignore + shouldBeCalled (fun call -> pipeline "" { + whenCmdArg "test1" "value" "description" true + stage "" { run call } + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { - cmdArgs [ "test1"; "value" ] + Assert.Throws(fun _ -> + shouldNotBeCalled (fun call -> pipeline "" { whenCmdArg "test1" "value" "description" false stage "" { run call } runImmediate - } + }) ) + |> ignore + + shouldBeCalled (fun call -> pipeline "" { + cmdArgs [ "test1"; "value" ] + whenCmdArg "test1" "value" "description" false + stage "" { run call } + runImmediate + }) diff --git a/Fun.Build.Tests/SequenceTests.fs b/Fun.Build.Tests/SequenceTests.fs index 5d56575..2d29f12 100644 --- a/Fun.Build.Tests/SequenceTests.fs +++ b/Fun.Build.Tests/SequenceTests.fs @@ -136,36 +136,33 @@ let ``nested stages should run in sequence`` () = Assert.Equal([ 1; 2; 3; 4; 5; 6; 7 ], calls) [] -let ``custom exit code should pass for stage`` () = - pipeline "" { - stage "" { - acceptExitCodes [| 99 |] - run (fun _ -> async { return 99 }) - } - runImmediate +let ``custom exit code should pass for stage`` () = pipeline "" { + stage "" { + acceptExitCodes [| 99 |] + run (fun _ -> async { return 99 }) } + runImmediate +} [] -let ``custom exit code should pass for pipeline`` () = - pipeline "" { - acceptExitCodes [| 99 |] - stage "" { run (fun _ -> async { return 99 }) } - runImmediate - } +let ``custom exit code should pass for pipeline`` () = pipeline "" { + acceptExitCodes [| 99 |] + stage "" { run (fun _ -> async { return 99 }) } + runImmediate +} [] -let ``custom exit code should pass for nested stage`` () = - pipeline "" { - stage "" { - acceptExitCodes [| 99 |] - stage "nested" { run (fun _ -> async { return 99 }) } - stage "nested2" { - acceptExitCodes [ 123 ] - run (fun _ -> 123) - } +let ``custom exit code should pass for nested stage`` () = pipeline "" { + stage "" { + acceptExitCodes [| 99 |] + stage "nested" { run (fun _ -> async { return 99 }) } + stage "nested2" { + acceptExitCodes [ 123 ] + run (fun _ -> 123) } - runImmediate } + runImmediate +} [] @@ -223,91 +220,81 @@ let ``continueOnStepFailure should work`` () = } Assert.Equal([ 1; 2; 3; 4 ], list) - shouldBeCalled (fun fn -> - pipeline "" { - stage "" { - paralle - continueOnStepFailure - run (fun _ -> Ok()) - run (fun _ -> Error "") - run (fun _ -> Ok()) - } - stage "" { run fn } - runImmediate + shouldBeCalled (fun fn -> pipeline "" { + stage "" { + paralle + continueOnStepFailure + run (fun _ -> Ok()) + run (fun _ -> Error "") + run (fun _ -> Ok()) } - ) + stage "" { run fn } + runImmediate + }) list.Clear() Assert.Throws(fun _ -> - shouldNotBeCalled (fun fn -> - pipeline "" { - stage "" { - continueOnStepFailure false - run (fun _ -> list.Add(1)) - run (fun _ -> - list.Add(2) - Error "" - ) - run (fun _ -> Ok()) - } - stage "" { run fn } - runImmediate + shouldNotBeCalled (fun fn -> pipeline "" { + stage "" { + continueOnStepFailure false + run (fun _ -> list.Add(1)) + run (fun _ -> + list.Add(2) + Error "" + ) + run (fun _ -> Ok()) } - ) + stage "" { run fn } + runImmediate + }) ) |> ignore Assert.Equal([ 1; 2 ], list) Assert.Throws(fun _ -> - shouldNotBeCalled (fun fn -> - pipeline "" { - stage "" { - paralle - continueOnStepFailure false - run (fun _ -> Ok()) - run (fun _ -> Error "") - run (fun _ -> Ok()) - } - stage "" { run fn } - runImmediate + shouldNotBeCalled (fun fn -> pipeline "" { + stage "" { + paralle + continueOnStepFailure false + run (fun _ -> Ok()) + run (fun _ -> Error "") + run (fun _ -> Ok()) } - ) + stage "" { run fn } + runImmediate + }) ) |> ignore list.Clear() Assert.Throws(fun _ -> - shouldNotBeCalled (fun fn -> - pipeline "" { - stage "" { - run (fun _ -> list.Add(1)) - run (fun _ -> - list.Add(2) - Error "" - ) - run (fun _ -> Ok()) - } - stage "" { run fn } - runImmediate + shouldNotBeCalled (fun fn -> pipeline "" { + stage "" { + run (fun _ -> list.Add(1)) + run (fun _ -> + list.Add(2) + Error "" + ) + run (fun _ -> Ok()) } - ) + stage "" { run fn } + runImmediate + }) ) |> ignore Assert.Equal([ 1; 2 ], list) Assert.Throws(fun _ -> - shouldNotBeCalled (fun fn -> - pipeline "" { - stage "" { - paralle - run (fun _ -> Ok()) - run (fun _ -> Error "") - run (fun _ -> Ok()) - } - stage "" { run fn } - runImmediate + shouldNotBeCalled (fun fn -> pipeline "" { + stage "" { + paralle + run (fun _ -> Ok()) + run (fun _ -> Error "") + run (fun _ -> Ok()) } - ) + stage "" { run fn } + runImmediate + }) ) |> ignore @@ -334,9 +321,27 @@ let ``continueOnStepFailure should work`` () = [] let ``continueStepsOnFailure should work`` () = let list = System.Collections.Generic.List() + Assert.Throws(fun _ -> pipeline "" { + stage "" { + continueStepsOnFailure + run (fun _ -> list.Add(1)) + run (fun _ -> + list.Add(2) + Error "" + ) + run (fun _ -> list.Add(3)) + } + stage "" { run (fun _ -> list.Add(4)) } + runImmediate + }) + |> ignore + Assert.Equal([ 1; 2; 3 ], list) + + list.Clear() Assert.Throws(fun _ -> - pipeline "" { + shouldNotBeCalled (fun fn -> pipeline "" { stage "" { + paralle continueStepsOnFailure run (fun _ -> list.Add(1)) run (fun _ -> @@ -345,76 +350,50 @@ let ``continueStepsOnFailure should work`` () = ) run (fun _ -> list.Add(3)) } - stage "" { run (fun _ -> list.Add(4)) } + stage "" { run fn } runImmediate - } + }) ) |> ignore - Assert.Equal([ 1; 2; 3 ], list) + Assert.Equal([ 1; 2; 3 ], Seq.sort list) list.Clear() - Assert.Throws(fun _ -> - shouldNotBeCalled (fun fn -> - pipeline "" { - stage "" { - paralle - continueStepsOnFailure - run (fun _ -> list.Add(1)) - run (fun _ -> - list.Add(2) - Error "" - ) - run (fun _ -> list.Add(3)) - } - stage "" { run fn } - runImmediate - } - ) - ) + Assert.Throws(fun _ -> pipeline "" { + stage "" { + continueStepsOnFailure false + run (fun _ -> list.Add(1)) + run (fun _ -> + list.Add(2) + Error "" + ) + run (fun _ -> list.Add(3)) + } + stage "" { run (fun _ -> list.Add(4)) } + runImmediate + }) |> ignore - Assert.Equal([ 1; 2; 3 ], Seq.sort list) + Assert.Equal([ 1; 2 ], list) list.Clear() Assert.Throws(fun _ -> - pipeline "" { + shouldNotBeCalled (fun fn -> pipeline "" { stage "" { + paralle continueStepsOnFailure false run (fun _ -> list.Add(1)) - run (fun _ -> + run (fun _ -> async { + do! Async.Sleep 1000 list.Add(2) - Error "" - ) - run (fun _ -> list.Add(3)) + return Error "" + }) + run (fun _ -> async { + do! Async.Sleep 3000 + list.Add(3) + }) } - stage "" { run (fun _ -> list.Add(4)) } + stage "" { run fn } runImmediate - } - ) - |> ignore - Assert.Equal([ 1; 2 ], list) - - list.Clear() - Assert.Throws(fun _ -> - shouldNotBeCalled (fun fn -> - pipeline "" { - stage "" { - paralle - continueStepsOnFailure false - run (fun _ -> list.Add(1)) - run (fun _ -> async { - do! Async.Sleep 1000 - list.Add(2) - return Error "" - }) - run (fun _ -> async { - do! Async.Sleep 3000 - list.Add(3) - }) - } - stage "" { run fn } - runImmediate - } - ) + }) ) |> ignore Assert.Equal([ 1; 2 ], list) @@ -461,46 +440,42 @@ let ``continueStageOnFailure should work`` () = Assert.Equal([ 1; 2; 4 ], Seq.sort list) list.Clear() - Assert.Throws(fun _ -> - pipeline "" { - stage "" { - continueStepsOnFailure true - continueStageOnFailure false - run (fun _ -> list.Add(1)) - run (fun _ -> - list.Add(2) - Error "" - ) - run (fun _ -> list.Add(3)) - } - stage "" { run (fun _ -> list.Add(4)) } - runImmediate + Assert.Throws(fun _ -> pipeline "" { + stage "" { + continueStepsOnFailure true + continueStageOnFailure false + run (fun _ -> list.Add(1)) + run (fun _ -> + list.Add(2) + Error "" + ) + run (fun _ -> list.Add(3)) } - ) + stage "" { run (fun _ -> list.Add(4)) } + runImmediate + }) |> ignore Assert.Equal([ 1; 2; 3 ], list) list.Clear() - Assert.Throws(fun _ -> - pipeline "" { - stage "" { - paralle - continueStepsOnFailure true - continueStageOnFailure false - run (fun _ -> list.Add(1)) - run (fun _ -> - list.Add(2) - Error "" - ) - run (fun _ -> async { - do! Async.Sleep 200 - list.Add(3) - }) - } - stage "" { run (fun _ -> list.Add(4)) } - runImmediate + Assert.Throws(fun _ -> pipeline "" { + stage "" { + paralle + continueStepsOnFailure true + continueStageOnFailure false + run (fun _ -> list.Add(1)) + run (fun _ -> + list.Add(2) + Error "" + ) + run (fun _ -> async { + do! Async.Sleep 200 + list.Add(3) + }) } - ) + stage "" { run (fun _ -> list.Add(4)) } + runImmediate + }) |> ignore Assert.Equal([ 1; 2; 3 ], Seq.sort list) @@ -508,23 +483,21 @@ let ``continueStageOnFailure should work`` () = [] let ``continueStepsOnFailure for nested stage should work`` () = let list = System.Collections.Generic.List() - Assert.Throws(fun _ -> - pipeline "" { + Assert.Throws(fun _ -> pipeline "" { + stage "" { + continueStepsOnFailure + run (fun _ -> list.Add(1)) stage "" { - continueStepsOnFailure - run (fun _ -> list.Add(1)) - stage "" { - run (fun _ -> - list.Add(2) - Error "" - ) - } - run (fun _ -> list.Add(3)) + run (fun _ -> + list.Add(2) + Error "" + ) } - stage "" { run (fun _ -> list.Add(4)) } - runImmediate + run (fun _ -> list.Add(3)) } - ) + stage "" { run (fun _ -> list.Add(4)) } + runImmediate + }) |> ignore Assert.Equal([ 1; 2; 3 ], list) @@ -550,26 +523,24 @@ let ``continueStepsOnFailure for nested stage should work`` () = [] let ``pipeline should be terminated correctly when parallel step are failed`` () = - Assert.Throws(fun _ -> - pipeline "" { + Assert.Throws(fun _ -> pipeline "" { + stage "" { + paralle + stage "timer" { + whenWindows + run (fun ctx -> ctx.RunCommand("timeout /t 10")) + } + stage "timer" { + whenNot { platformWindows } + run (fun ctx -> ctx.RunCommand("sleep 10")) + } stage "" { - paralle - stage "timer" { - whenWindows - run (fun ctx -> ctx.RunCommand("timeout /t 10")) - } - stage "timer" { - whenNot { platformWindows } - run (fun ctx -> ctx.RunCommand("sleep 10")) - } - stage "" { - run (Async.Sleep 1000) - run (fun _ -> - failwith "Demo" - () - ) - } + run (Async.Sleep 1000) + run (fun _ -> + failwith "Demo" + () + ) } - runImmediate } - ) + runImmediate + }) diff --git a/Fun.Build.Tests/StageContextExtensions.fs b/Fun.Build.Tests/StageContextExtensions.fs index 6766521..139b718 100644 --- a/Fun.Build.Tests/StageContextExtensions.fs +++ b/Fun.Build.Tests/StageContextExtensions.fs @@ -7,12 +7,11 @@ open Fun.Build.StageContextExtensionsInternal [] let ``TryGetCmdArgOrEnvVar should work`` () = - let pipeline = - pipeline "" { - envVars [ "test1", "e1"; "test2", "e1"; "test3", "e1" ] - cmdArgs [ "test3"; "c1" ] - stage "" { envVars [ "test2", "e2" ] } - } + let pipeline = pipeline "" { + envVars [ "test1", "e1"; "test2", "e1"; "test3", "e1" ] + cmdArgs [ "test3"; "c1" ] + stage "" { envVars [ "test2", "e2" ] } + } Assert.Equal(ValueNone, pipeline.Stages[0].TryGetCmdArgOrEnvVar "abc") Assert.Equal(ValueSome "e1", pipeline.Stages[0].TryGetCmdArgOrEnvVar "test1") @@ -22,11 +21,10 @@ let ``TryGetCmdArgOrEnvVar should work`` () = [] let ``GetAllEnvVars should work`` () = - let pipeline = - pipeline "" { - envVars [ "test1", "e1"; "test2", "e1"; "test3", "e3" ] - stage "" { envVars [ "test2", "e2" ] } - } + let pipeline = pipeline "" { + envVars [ "test1", "e1"; "test2", "e1"; "test3", "e3" ] + stage "" { envVars [ "test2", "e2" ] } + } let result = pipeline.Stages[0].GetAllEnvVars() Assert.Equal("e1", Map.find "test1" result) @@ -36,23 +34,21 @@ let ``GetAllEnvVars should work`` () = [] let ``GetAllCmdArgs should work`` () = - let pipeline = - pipeline "" { - cmdArgs [ "test3"; "c1" ] - stage "" { echo "" } - } + let pipeline = pipeline "" { + cmdArgs [ "test3"; "c1" ] + stage "" { echo "" } + } Assert.Equal([ "test3"; "c1" ], pipeline.Stages[0].GetAllCmdArgs()) [] let ``workingDir should work`` () = - let pipeline = - pipeline "" { - workingDir "test1" - stage "" { workingDir "test2" } - stage "" { run ignore } - } + let pipeline = pipeline "" { + workingDir "test1" + stage "" { workingDir "test2" } + stage "" { run ignore } + } Assert.Equal(ValueSome "test1", pipeline.Stages[1].GetWorkingDir()) Assert.Equal(ValueSome "test2", pipeline.Stages[0].GetWorkingDir()) @@ -60,21 +56,19 @@ let ``workingDir should work`` () = [] let ``noPrefixForStep should work`` () = - let pipeline1 = - pipeline "" { - noPrefixForStep false - stage "" { noPrefixForStep false } - stage "" { run ignore } - } + let pipeline1 = pipeline "" { + noPrefixForStep false + stage "" { noPrefixForStep false } + stage "" { run ignore } + } Assert.Equal(false, pipeline1.Stages[0].GetNoPrefixForStep()) Assert.Equal(false, pipeline1.Stages[1].GetNoPrefixForStep()) - let pipeline2 = - pipeline "" { - stage "" { noPrefixForStep false } - stage "" { run ignore } - } + let pipeline2 = pipeline "" { + stage "" { noPrefixForStep false } + stage "" { run ignore } + } Assert.Equal(false, pipeline2.Stages[0].GetNoPrefixForStep()) Assert.Equal(true, pipeline2.Stages[1].GetNoPrefixForStep()) @@ -82,171 +76,161 @@ let ``noPrefixForStep should work`` () = [] let ``noStdRedirectForStep should work`` () = - let pipeline1 = - pipeline "" { - noStdRedirectForStep - stage "" { noStdRedirectForStep } - stage "" { run ignore } - } + let pipeline1 = pipeline "" { + noStdRedirectForStep + stage "" { noStdRedirectForStep } + stage "" { run ignore } + } Assert.Equal(true, pipeline1.Stages[0].GetNoStdRedirectForStep()) Assert.Equal(true, pipeline1.Stages[1].GetNoStdRedirectForStep()) - let pipeline2 = - pipeline "" { - stage "" { noStdRedirectForStep } - stage "" { run ignore } - } + let pipeline2 = pipeline "" { + stage "" { noStdRedirectForStep } + stage "" { run ignore } + } Assert.Equal(true, pipeline2.Stages[0].GetNoStdRedirectForStep()) Assert.Equal(false, pipeline2.Stages[1].GetNoStdRedirectForStep()) [] -let ``RunCommandCaptureOutput should work`` () = - pipeline "" { - stage "" { - whenAny { - platformOSX - platformLinux - } - run (fun ctx -> async { - let! result = ctx.RunCommandCaptureOutput "echo 42" - Assert.Equal(Ok "42\n", result) - }) +let ``RunCommandCaptureOutput should work`` () = pipeline "" { + stage "" { + whenAny { + platformOSX + platformLinux } - stage "" { - whenWindows - run (fun ctx -> async { - let! result = ctx.RunCommandCaptureOutput "powershell echo 42" - Assert.Equal(Ok "42\r\n", result) - }) - } - runImmediate + run (fun ctx -> async { + let! result = ctx.RunCommandCaptureOutput "echo 42" + Assert.Equal(Ok "42\n", result) + }) + } + stage "" { + whenWindows + run (fun ctx -> async { + let! result = ctx.RunCommandCaptureOutput "powershell echo 42" + Assert.Equal(Ok "42\r\n", result) + }) } + runImmediate +} [] -let ``RunCommandCaptureOutput in working directory should work`` () = - pipeline "" { - stage "" { - whenAny { - platformOSX - platformLinux - } - run (fun ctx -> async { - let tmpFolder = System.IO.Path.GetTempPath() - let! result = ctx.RunCommandCaptureOutput("echo 42", workingDir = tmpFolder) - Assert.Equal(Ok "42\n", result) - }) - } - stage "" { - whenWindows - run (fun ctx -> async { - let! result = ctx.RunCommandCaptureOutput "powershell echo 42" - Assert.Equal(Ok "42\r\n", result) - }) +let ``RunCommandCaptureOutput in working directory should work`` () = pipeline "" { + stage "" { + whenAny { + platformOSX + platformLinux } - runImmediate + run (fun ctx -> async { + let tmpFolder = System.IO.Path.GetTempPath() + let! result = ctx.RunCommandCaptureOutput("echo 42", workingDir = tmpFolder) + Assert.Equal(Ok "42\n", result) + }) + } + stage "" { + whenWindows + run (fun ctx -> async { + let! result = ctx.RunCommandCaptureOutput "powershell echo 42" + Assert.Equal(Ok "42\r\n", result) + }) } + runImmediate +} [] let ``RunCommandCaptureOutput should return an error if command failed`` () = Assert.Throws(fun _ -> - shouldBeCalled (fun call -> - pipeline "" { - stage "" { - run (fun ctx -> async { - let! result = ctx.RunCommandCaptureOutput "thisCmdDoesNotExist" - return () - }) - } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + stage "" { + run (fun ctx -> async { + let! result = ctx.RunCommandCaptureOutput "thisCmdDoesNotExist" + return () + }) } - ) + runImmediate + }) ) |> ignore [] -let ``RunCommandCaptureAll should return exit code, stdout and stderr`` () = - pipeline "" { - stage "" { - whenAny { - platformOSX - platformLinux - } - run (fun ctx -> async { - let! result = ctx.RunCommandCaptureAll "sh -c \"echo out; echo err >&2; exit 3\"" - Assert.Equal(3, result.ExitCode) - Assert.Equal("out\n", result.StandardOutput) - Assert.Equal("err\n", result.StandardError) - }) - } - stage "" { - whenWindows - run (fun ctx -> async { - let! result = ctx.RunCommandCaptureAll "powershell -Command \"echo out; [Console]::Error.WriteLine('err'); exit 3\"" - Assert.Equal(3, result.ExitCode) - Assert.Equal("out\r\n", result.StandardOutput) - Assert.Equal("err\r\n", result.StandardError) - }) +let ``RunCommandCaptureAll should return exit code, stdout and stderr`` () = pipeline "" { + stage "" { + whenAny { + platformOSX + platformLinux } - runImmediate + run (fun ctx -> async { + let! result = ctx.RunCommandCaptureAll "sh -c \"echo out; echo err >&2; exit 3\"" + Assert.Equal(3, result.ExitCode) + Assert.Equal("out\n", result.StandardOutput) + Assert.Equal("err\n", result.StandardError) + }) } + stage "" { + whenWindows + run (fun ctx -> async { + let! result = ctx.RunCommandCaptureAll "powershell -Command \"echo out; [Console]::Error.WriteLine('err'); exit 3\"" + Assert.Equal(3, result.ExitCode) + Assert.Equal("out\r\n", result.StandardOutput) + Assert.Equal("err\r\n", result.StandardError) + }) + } + runImmediate +} [] let ``RunCommandCaptureAll should not fail the stage on a non zero exit code`` () = - shouldBeCalled (fun call -> - pipeline "" { - stage "" { - whenAny { - platformOSX - platformLinux - } - run (fun ctx -> async { - let! result = ctx.RunCommandCaptureAll "sh -c \"exit 1\"" - Assert.Equal(1, result.ExitCode) - call () - }) - } - stage "" { - whenWindows - run (fun ctx -> async { - let! result = ctx.RunCommandCaptureAll "powershell -Command \"exit 1\"" - Assert.Equal(1, result.ExitCode) - call () - }) - } - runImmediate - } - ) - -[] -let ``RunSensitiveCommandCaptureAll should work`` () = - pipeline "" { + shouldBeCalled (fun call -> pipeline "" { stage "" { whenAny { platformOSX platformLinux } run (fun ctx -> async { - let! result = ctx.RunSensitiveCommandCaptureAll $"""echo {"42"}""" - Assert.Equal(0, result.ExitCode) - Assert.Equal("42\n", result.StandardOutput) - Assert.Equal("", result.StandardError) + let! result = ctx.RunCommandCaptureAll "sh -c \"exit 1\"" + Assert.Equal(1, result.ExitCode) + call () }) } stage "" { whenWindows run (fun ctx -> async { - let! result = ctx.RunSensitiveCommandCaptureAll $"""powershell echo {"42"}""" - Assert.Equal(0, result.ExitCode) - Assert.Equal("42\r\n", result.StandardOutput) - Assert.Equal("", result.StandardError) + let! result = ctx.RunCommandCaptureAll "powershell -Command \"exit 1\"" + Assert.Equal(1, result.ExitCode) + call () }) } runImmediate + }) + +[] +let ``RunSensitiveCommandCaptureAll should work`` () = pipeline "" { + stage "" { + whenAny { + platformOSX + platformLinux + } + run (fun ctx -> async { + let! result = ctx.RunSensitiveCommandCaptureAll $"""echo {"42"}""" + Assert.Equal(0, result.ExitCode) + Assert.Equal("42\n", result.StandardOutput) + Assert.Equal("", result.StandardError) + }) } + stage "" { + whenWindows + run (fun ctx -> async { + let! result = ctx.RunSensitiveCommandCaptureAll $"""powershell echo {"42"}""" + Assert.Equal(0, result.ExitCode) + Assert.Equal("42\r\n", result.StandardOutput) + Assert.Equal("", result.StandardError) + }) + } + runImmediate +} [] @@ -254,102 +238,90 @@ let ``Soft cancel should work`` () = let mutable i = 0 let mutable j = 0 - shouldBeCalled (fun call -> - pipeline "" { - timeout 2 - stage "" { - paralle - run (fun _ -> async { - while true do - do! Async.Sleep 100 - }) - run (fun ctx -> async { - while true do - do! Async.Sleep 100 - j <- j + 1 - printfn $"task2 {i}" - if i > 3 then ctx.SoftCancelStep() - }) - run (fun ctx -> async { - while true do - do! Async.Sleep 100 - i <- i + 1 - printfn $"task1 {i}" - if i > 5 then ctx.SoftCancelStage() - }) - } - stage "" { run call } - runImmediate + shouldBeCalled (fun call -> pipeline "" { + timeout 2 + stage "" { + paralle + run (fun _ -> async { + while true do + do! Async.Sleep 100 + }) + run (fun ctx -> async { + while true do + do! Async.Sleep 100 + j <- j + 1 + printfn $"task2 {i}" + if i > 3 then ctx.SoftCancelStep() + }) + run (fun ctx -> async { + while true do + do! Async.Sleep 100 + i <- i + 1 + printfn $"task1 {i}" + if i > 5 then ctx.SoftCancelStage() + }) } - ) + stage "" { run call } + runImmediate + }) Assert.True(10 <= i + j) [] let ``FailIfNoActiveSubStage`` () = - Assert.Throws(fun _ -> - pipeline "" { - stage "" { - failIfNoActiveSubStage - stage "" { when' false } - } - runImmediate + Assert.Throws(fun _ -> pipeline "" { + stage "" { + failIfNoActiveSubStage + stage "" { when' false } } - ) + runImmediate + }) |> ignore - Assert.Throws(fun _ -> - pipeline "" { - stage "" { - failIfNoActiveSubStage - echo "" - } - runImmediate + Assert.Throws(fun _ -> pipeline "" { + stage "" { + failIfNoActiveSubStage + echo "" } - ) + runImmediate + }) |> ignore - shouldBeCalled (fun call -> - pipeline "" { + shouldBeCalled (fun call -> pipeline "" { + stage "" { + failIfNoActiveSubStage + stage "" { when' false } stage "" { - failIfNoActiveSubStage - stage "" { when' false } - stage "" { - when' true - run (ignore >> call) - } + when' true + run (ignore >> call) } - runImmediate } - ) + runImmediate + }) - shouldBeCalled (fun call -> - pipeline "" { + shouldBeCalled (fun call -> pipeline "" { + stage "" { + failIfNoActiveSubStage + echo "" stage "" { - failIfNoActiveSubStage - echo "" - stage "" { - when' true - run (ignore >> call) - } + when' true + run (ignore >> call) } - runImmediate } - ) + runImmediate + }) [] let ``runHttpHealthCheck should work`` () = - shouldBeCalled (fun fn -> - pipeline "" { - stage "" { - runHttpHealthCheck "https://www.bing.com/" - run fn - } - runImmediate + shouldBeCalled (fun fn -> pipeline "" { + stage "" { + runHttpHealthCheck "https://www.bing.com/" + run fn } - ) + runImmediate + }) Assert.Throws(fun _ -> use cts = new System.Threading.CancellationTokenSource(3000) diff --git a/Fun.Build.Tests/TimeoutTests.fs b/Fun.Build.Tests/TimeoutTests.fs index ce255d7..5104da8 100644 --- a/Fun.Build.Tests/TimeoutTests.fs +++ b/Fun.Build.Tests/TimeoutTests.fs @@ -6,102 +6,88 @@ open Fun.Build [] let ``timeout should work`` () = - shouldBeCalled (fun call -> - pipeline "timeout" { + shouldBeCalled (fun call -> pipeline "timeout" { + timeout 1 + stage "timeout" { + run ( + async { + do! Async.Sleep 100 + call () + } + ) + } + runImmediate + }) + + Assert.Throws(fun _ -> + shouldNotBeCalled (fun call -> pipeline "timeout" { timeout 1 stage "timeout" { run ( async { - do! Async.Sleep 100 + do! Async.Sleep 2000 call () } ) } runImmediate - } - ) - - Assert.Throws(fun _ -> - shouldNotBeCalled (fun call -> - pipeline "timeout" { - timeout 1 - stage "timeout" { - run ( - async { - do! Async.Sleep 2000 - call () - } - ) - } - runImmediate - } - ) + }) ) |> ignore - Assert.Throws(fun _ -> - pipeline "timeout" { - timeout 2 - stage "timeout1" { run (Async.Sleep 1000) } - stage "timeout2" { run (Async.Sleep 1100) } - runImmediate - } - ) + Assert.Throws(fun _ -> pipeline "timeout" { + timeout 2 + stage "timeout1" { run (Async.Sleep 1000) } + stage "timeout2" { run (Async.Sleep 1100) } + runImmediate + }) [] let ``timeoutForStage should work`` () = - Assert.Throws(fun _ -> - pipeline "timeoutForStage" { - timeoutForStage 1 - stage "timeoutForStage" { run (Async.Sleep 2100) } - runImmediate - } - ) + Assert.Throws(fun _ -> pipeline "timeoutForStage" { + timeoutForStage 1 + stage "timeoutForStage" { run (Async.Sleep 2100) } + runImmediate + }) |> ignore - Assert.Throws(fun _ -> - pipeline "timeoutForStage" { - timeoutForStage 2 - stage "timeoutForStage" { - timeout 1 - run (Async.Sleep 1100) - } - runImmediate + Assert.Throws(fun _ -> pipeline "timeoutForStage" { + timeoutForStage 2 + stage "timeoutForStage" { + timeout 1 + run (Async.Sleep 1100) } - ) + runImmediate + }) [] let ``timeoutForStep should work`` () = Assert.Throws(fun _ -> - shouldNotBeCalled (fun call -> - pipeline "timeoutForStep" { - timeoutForStep 1 - stage "timeoutForStep" { - run (Async.Sleep 500) - run (Async.Sleep 1100) - run call - } - runImmediate + shouldNotBeCalled (fun call -> pipeline "timeoutForStep" { + timeoutForStep 1 + stage "timeoutForStep" { + run (Async.Sleep 500) + run (Async.Sleep 1100) + run call } - ) + runImmediate + }) ) |> ignore Assert.Throws(fun _ -> - shouldNotBeCalled (fun call -> - pipeline "timeoutForStep" { - timeoutForStep 2 - stage "timeoutForStep" { - timeoutForStep 1 - run (Async.Sleep 500) - run (Async.Sleep 1100) - run call - } - runImmediate + shouldNotBeCalled (fun call -> pipeline "timeoutForStep" { + timeoutForStep 2 + stage "timeoutForStep" { + timeoutForStep 1 + run (Async.Sleep 500) + run (Async.Sleep 1100) + run call } - ) + runImmediate + }) ) @@ -109,94 +95,82 @@ let ``timeoutForStep should work`` () = [] let ``nested stage timeout should work`` () = Assert.Throws(fun _ -> - shouldNotBeCalled (fun call -> - pipeline "timeout" { - timeout 1 + shouldNotBeCalled (fun call -> pipeline "timeout" { + timeout 1 + stage "" { stage "" { - stage "" { - run (Async.Sleep 500) - run (Async.Sleep 1100) - run call - } + run (Async.Sleep 500) + run (Async.Sleep 1100) + run call } - runImmediate } - ) + runImmediate + }) ) |> ignore Assert.Throws(fun _ -> - shouldNotBeCalled (fun call -> - pipeline "timeout" { - timeout 1 + shouldNotBeCalled (fun call -> pipeline "timeout" { + timeout 1 + stage "" { + timeout 2 stage "" { - timeout 2 - stage "" { - run (Async.Sleep 500) - run (Async.Sleep 1100) - run call - } + run (Async.Sleep 500) + run (Async.Sleep 1100) + run call } - runImmediate } - ) + runImmediate + }) ) |> ignore [] let ``nested stage timeoutForStep should work`` () = - Assert.Throws(fun _ -> - pipeline "timeoutForStep" { - timeoutForStep 1 - stage "" { stage "" { run (Async.Sleep 1100) } } - runImmediate - } - ) + Assert.Throws(fun _ -> pipeline "timeoutForStep" { + timeoutForStep 1 + stage "" { stage "" { run (Async.Sleep 1100) } } + runImmediate + }) |> ignore Assert.Throws(fun _ -> - shouldBeCalled (fun call -> - pipeline "timeoutForStep" { - timeoutForStep 1 + shouldBeCalled (fun call -> pipeline "timeoutForStep" { + timeoutForStep 1 + stage "" { stage "" { - stage "" { - timeoutForStep 2 - run (Async.Sleep 1100) - run call - } + timeoutForStep 2 + run (Async.Sleep 1100) + run call } - runImmediate } - ) + runImmediate + }) ) |> ignore [] let ``nested stage timeoutForStage should work`` () = - Assert.Throws(fun _ -> - pipeline "timeoutForStage" { - timeoutForStage 1 - stage "" { stage "" { run (Async.Sleep 1100) } } - runImmediate - } - ) + Assert.Throws(fun _ -> pipeline "timeoutForStage" { + timeoutForStage 1 + stage "" { stage "" { run (Async.Sleep 1100) } } + runImmediate + }) |> ignore Assert.Throws(fun _ -> - shouldBeCalled (fun call -> - pipeline "timeoutForStage" { - timeoutForStage 1 + shouldBeCalled (fun call -> pipeline "timeoutForStage" { + timeoutForStage 1 + stage "" { stage "" { - stage "" { - timeout 2 - run (Async.Sleep 1100) - run call - } + timeout 2 + run (Async.Sleep 1100) + run call } - runImmediate } - ) + runImmediate + }) ) |> ignore diff --git a/Fun.Build/BuiltinCmds.fs b/Fun.Build/BuiltinCmds.fs index a7c4913..1a1a8a3 100644 --- a/Fun.Build/BuiltinCmds.fs +++ b/Fun.Build/BuiltinCmds.fs @@ -50,40 +50,39 @@ module BuiltinCmdsInternal = ?disablePrintOutput: bool, ?disablePrintCommand: bool, ?cancellationToken: CancellationToken - ) : Async = - async { - let disablePrintOutput = defaultArg disablePrintOutput false - let disablePrintCommand = defaultArg disablePrintCommand false - let command = ctx.BuildCommand(commandStr, ?workingDir = workingDir) - let noPrefixForStep = ctx.GetNoPrefixForStep() - let prefix = - if noPrefixForStep then - "" - else - match step with - | Some i -> ctx.BuildStepPrefix i - | None -> ctx.GetNamePath() - - if not noPrefixForStep then AnsiConsole.Markup $"[green]{prefix}[/] " - if not disablePrintCommand then AnsiConsole.WriteLine commandLogString - - let ct = defaultArg cancellationToken CancellationToken.None - - return! - Process.StartAsync( - command, - commandLogString, - prefix, - printOutput = (not disablePrintOutput && not (ctx.GetNoStdRedirectForStep())), - captureOutput = true, - cancellationToken = ct - ) - } + ) : Async = async { + let disablePrintOutput = defaultArg disablePrintOutput false + let disablePrintCommand = defaultArg disablePrintCommand false + let command = ctx.BuildCommand(commandStr, ?workingDir = workingDir) + let noPrefixForStep = ctx.GetNoPrefixForStep() + let prefix = + if noPrefixForStep then + "" + else + match step with + | Some i -> ctx.BuildStepPrefix i + | None -> ctx.GetNamePath() + + if not noPrefixForStep then AnsiConsole.Markup $"[green]{prefix}[/] " + if not disablePrintCommand then AnsiConsole.WriteLine commandLogString + + let ct = defaultArg cancellationToken CancellationToken.None + + return! + Process.StartAsync( + command, + commandLogString, + prefix, + printOutput = (not disablePrintOutput && not (ctx.GetNoStdRedirectForStep())), + captureOutput = true, + cancellationToken = ct + ) + } /// Add command to context - member ctx.AddCommandStep(commandStrFn: StageContext -> Async, ?cancellationToken: CancellationToken) = - { ctx with + member ctx.AddCommandStep(commandStrFn: StageContext -> Async, ?cancellationToken: CancellationToken) = { + ctx with Steps = ctx.Steps @ [ @@ -92,7 +91,7 @@ module BuiltinCmdsInternal = return! ctx.RunCommand(commandStr, i, cancellationToken = defaultArg cancellationToken CancellationToken.None) }) ] - } + } [] @@ -112,40 +111,39 @@ module BuiltinCmds = ?disablePrintOutput: bool, ?disablePrintCommand: bool, ?cancellationToken: CancellationToken - ) = - async { - let disablePrintOutput = defaultArg disablePrintOutput false - let disablePrintCommand = defaultArg disablePrintCommand false - let command = ctx.BuildCommand(commandStr, ?workingDir = workingDir) - let noPrefixForStep = ctx.GetNoPrefixForStep() - let prefix = - if noPrefixForStep then - "" - else - match step with - | Some i -> ctx.BuildStepPrefix i - | None -> ctx.GetNamePath() - - if not noPrefixForStep then AnsiConsole.Markup $"[green]{prefix}[/] " - if not disablePrintCommand then AnsiConsole.WriteLine commandStr - - let ct = defaultArg cancellationToken CancellationToken.None - - let! result = - Process.StartAsync( - command, - commandStr, - prefix, - printOutput = (not disablePrintOutput && not (ctx.GetNoStdRedirectForStep())), - cancellationToken = ct - ) - - return - if ct.IsCancellationRequested then - Ok() - else - ctx.MapExitCodeToResult result.ExitCode - } + ) = async { + let disablePrintOutput = defaultArg disablePrintOutput false + let disablePrintCommand = defaultArg disablePrintCommand false + let command = ctx.BuildCommand(commandStr, ?workingDir = workingDir) + let noPrefixForStep = ctx.GetNoPrefixForStep() + let prefix = + if noPrefixForStep then + "" + else + match step with + | Some i -> ctx.BuildStepPrefix i + | None -> ctx.GetNamePath() + + if not noPrefixForStep then AnsiConsole.Markup $"[green]{prefix}[/] " + if not disablePrintCommand then AnsiConsole.WriteLine commandStr + + let ct = defaultArg cancellationToken CancellationToken.None + + let! result = + Process.StartAsync( + command, + commandStr, + prefix, + printOutput = (not disablePrintOutput && not (ctx.GetNoStdRedirectForStep())), + cancellationToken = ct + ) + + return + if ct.IsCancellationRequested then + Ok() + else + ctx.MapExitCodeToResult result.ExitCode + } /// /// Run a command string with current context, and return the standard output if the exit code is acceptable. @@ -161,42 +159,41 @@ module BuiltinCmds = ?disablePrintOutput: bool, ?disablePrintCommand: bool, ?cancellationToken: CancellationToken - ) = - async { - let disablePrintOutput = defaultArg disablePrintOutput false - let disablePrintCommand = defaultArg disablePrintCommand false - let command = ctx.BuildCommand(commandStr, ?workingDir = workingDir) - let noPrefixForStep = ctx.GetNoPrefixForStep() - let prefix = - if noPrefixForStep then - "" - else - match step with - | Some i -> ctx.BuildStepPrefix i - | None -> ctx.GetNamePath() - - if not noPrefixForStep then AnsiConsole.Markup $"[green]{prefix}[/] " - if not disablePrintCommand then AnsiConsole.WriteLine commandStr - - let ct = defaultArg cancellationToken CancellationToken.None - - let! result = - Process.StartAsync( - command, - commandStr, - prefix, - printOutput = (not disablePrintOutput && not (ctx.GetNoStdRedirectForStep())), - captureOutput = true, - cancellationToken = ct - ) - - if ct.IsCancellationRequested then - return Ok result.StandardOutput - else if ctx.IsAcceptableExitCode result.ExitCode then - return Ok result.StandardOutput + ) = async { + let disablePrintOutput = defaultArg disablePrintOutput false + let disablePrintCommand = defaultArg disablePrintCommand false + let command = ctx.BuildCommand(commandStr, ?workingDir = workingDir) + let noPrefixForStep = ctx.GetNoPrefixForStep() + let prefix = + if noPrefixForStep then + "" else - return Error "Exit code is not indicating as successful." - } + match step with + | Some i -> ctx.BuildStepPrefix i + | None -> ctx.GetNamePath() + + if not noPrefixForStep then AnsiConsole.Markup $"[green]{prefix}[/] " + if not disablePrintCommand then AnsiConsole.WriteLine commandStr + + let ct = defaultArg cancellationToken CancellationToken.None + + let! result = + Process.StartAsync( + command, + commandStr, + prefix, + printOutput = (not disablePrintOutput && not (ctx.GetNoStdRedirectForStep())), + captureOutput = true, + cancellationToken = ct + ) + + if ct.IsCancellationRequested then + return Ok result.StandardOutput + else if ctx.IsAcceptableExitCode result.ExitCode then + return Ok result.StandardOutput + else + return Error "Exit code is not indicating as successful." + } /// Run a command string with current context, and encrypt the string for logging @@ -208,45 +205,44 @@ module BuiltinCmds = ?disablePrintOutput: bool, ?disablePrintCommand: bool, ?cancellationToken: CancellationToken - ) : Async> = - async { - let disablePrintOutput = defaultArg disablePrintOutput false - let disablePrintCommand = defaultArg disablePrintCommand false - let command = ctx.BuildCommand(commandStr.ToString(), ?workingDir = workingDir) - let noPrefixForStep = ctx.GetNoPrefixForStep() - let args: obj[] = Array.create commandStr.ArgumentCount "*" - let encryptiedStr = String.Format(commandStr.Format, args) - - let prefix = - if noPrefixForStep then - "" - else - match step with - | Some i -> ctx.BuildStepPrefix i - | None -> ctx.GetNamePath() - - if not noPrefixForStep then AnsiConsole.Markup $"[green]{prefix}[/] " - if not disablePrintCommand then AnsiConsole.WriteLine encryptiedStr - - let ct = defaultArg cancellationToken CancellationToken.None - - let! result = - Process.StartAsync( - command, - encryptiedStr, - prefix, - printOutput = (not disablePrintOutput && not (ctx.GetNoStdRedirectForStep())), - captureOutput = true, - cancellationToken = ct - ) + ) : Async> = async { + let disablePrintOutput = defaultArg disablePrintOutput false + let disablePrintCommand = defaultArg disablePrintCommand false + let command = ctx.BuildCommand(commandStr.ToString(), ?workingDir = workingDir) + let noPrefixForStep = ctx.GetNoPrefixForStep() + let args: obj[] = Array.create commandStr.ArgumentCount "*" + let encryptiedStr = String.Format(commandStr.Format, args) - if ct.IsCancellationRequested then - return Ok result.StandardOutput - else if ctx.IsAcceptableExitCode result.ExitCode then - return Ok result.StandardOutput + let prefix = + if noPrefixForStep then + "" else - return Error "Exit code is not indicating as successful." - } + match step with + | Some i -> ctx.BuildStepPrefix i + | None -> ctx.GetNamePath() + + if not noPrefixForStep then AnsiConsole.Markup $"[green]{prefix}[/] " + if not disablePrintCommand then AnsiConsole.WriteLine encryptiedStr + + let ct = defaultArg cancellationToken CancellationToken.None + + let! result = + Process.StartAsync( + command, + encryptiedStr, + prefix, + printOutput = (not disablePrintOutput && not (ctx.GetNoStdRedirectForStep())), + captureOutput = true, + cancellationToken = ct + ) + + if ct.IsCancellationRequested then + return Ok result.StandardOutput + else if ctx.IsAcceptableExitCode result.ExitCode then + return Ok result.StandardOutput + else + return Error "Exit code is not indicating as successful." + } /// /// Run a command string with current context, and return the exit code, standard output and standard error diff --git a/Fun.Build/Changelog.fs b/Fun.Build/Changelog.fs index 370cf35..90d9a1d 100644 --- a/Fun.Build/Changelog.fs +++ b/Fun.Build/Changelog.fs @@ -51,10 +51,9 @@ type Changelog = match version with | None -> None | Some v -> - Some - {| - Version = v - Preview = preview - ReleaseNotes = releaseNotes.ToString() - DateTime = dateTime - |} + Some {| + Version = v + Preview = preview + ReleaseNotes = releaseNotes.ToString() + DateTime = dateTime + |} diff --git a/Fun.Build/ConditionsBuilder.fs b/Fun.Build/ConditionsBuilder.fs index 2c21d8f..b37b024 100644 --- a/Fun.Build/ConditionsBuilder.fs +++ b/Fun.Build/ConditionsBuilder.fs @@ -35,10 +35,10 @@ module Internal = member ctx.WhenStage(stage: StageContext) = match ctx.GetMode() with | Mode.Execution -> - let stage = - { stage with + let stage = { + stage with ParentContext = ValueSome(StageParent.Stage ctx) - } + } let result, _ = stage.Run(StageIndex.Condition, System.Threading.CancellationToken.None) result | Mode.Verification -> @@ -79,15 +79,12 @@ module Internal = member ctx.WhenEnvArg(name: string, ?argValue, ?description, ?isOptional) = let argValue = defaultArg argValue "" - ctx.WhenEnvArg - { - EnvArg.Name = name - Description = description - Values = [ - if String.IsNullOrEmpty argValue |> not then argValue - ] - IsOptional = defaultArg isOptional false - } + ctx.WhenEnvArg { + EnvArg.Name = name + Description = description + Values = [ if String.IsNullOrEmpty argValue |> not then argValue ] + IsOptional = defaultArg isOptional false + } member ctx.WhenCmdArg(info: CmdArg) = @@ -124,15 +121,12 @@ module Internal = member ctx.WhenCmdArg(name: CmdName, ?argValue: string, ?description, ?isOptional) = let argValue = defaultArg argValue "" - ctx.WhenCmdArg - { - CmdArg.Name = name - Description = description - Values = [ - if String.IsNullOrEmpty argValue |> not then argValue - ] - IsOptional = defaultArg isOptional false - } + ctx.WhenCmdArg { + CmdArg.Name = name + Description = description + Values = [ if String.IsNullOrEmpty argValue |> not then argValue ] + IsOptional = defaultArg isOptional false + } member ctx.WhenBranch(branches: string seq) = @@ -267,13 +261,8 @@ type ConditionsBuilder() = [] member inline _.cmdArg - ( - [] builder: BuildConditions, - argKeyLongName: string, - argValue: string, - description: string, - isOptional: bool - ) = + ([] builder: BuildConditions, argKeyLongName: string, argValue: string, description: string, isOptional: bool) + = buildConditions builder (fun ctx -> ctx.WhenCmdArg(CmdName.LongName argKeyLongName, argValue = argValue, description = description, isOptional = isOptional)) @@ -444,13 +433,8 @@ type PipelineBuilder with /// Set if pipeline can run by check the command line args. [] member inline _.whenCmdArg - ( - [] build: BuildPipeline, - argKeyLongName: string, - argValue: string, - description: string, - isOptional: bool - ) = + ([] build: BuildPipeline, argKeyLongName: string, argValue: string, description: string, isOptional: bool) + = buildPipelineVerification build (fun ctx -> @@ -498,14 +482,14 @@ type WhenAnyBuilder() = | Mode.CommandHelp { Verbose = true } -> AnsiConsole.MarkupLine $"[olive]{ctx.BuildIndent()}when any below conditions are met[/]" | _ -> () - let indentCtx = - { StageContext.Create " " with + let indentCtx = { + StageContext.Create " " with ParentContext = ctx.ParentContext - } - let newCtx = - { ctx with + } + let newCtx = { + ctx with ParentContext = ValueSome(StageParent.Stage indentCtx) - } + } builder.Invoke [] |> Seq.iter (fun fn -> fn newCtx |> ignore) false ) @@ -524,14 +508,14 @@ type WhenAllBuilder() = | Mode.CommandHelp { Verbose = true } -> AnsiConsole.MarkupLine $"[olive]{ctx.BuildIndent()}when all below conditions are met[/]" | _ -> () - let indentCtx = - { StageContext.Create " " with + let indentCtx = { + StageContext.Create " " with ParentContext = ctx.ParentContext - } - let newCtx = - { ctx with + } + let newCtx = { + ctx with ParentContext = ValueSome(StageParent.Stage indentCtx) - } + } builder.Invoke [] |> Seq.iter (fun fn -> fn newCtx |> ignore) false ) @@ -551,14 +535,14 @@ type WhenNotBuilder() = AnsiConsole.MarkupLine $"[olive]{ctx.BuildIndent()}when all below conditions are [bold red]NOT[/] met[/]" | _ -> () - let indentCtx = - { StageContext.Create " " with + let indentCtx = { + StageContext.Create " " with ParentContext = ctx.ParentContext - } - let newCtx = - { ctx with + } + let newCtx = { + ctx with ParentContext = ValueSome(StageParent.Stage indentCtx) - } + } builder.Invoke [] |> Seq.iter (fun fn -> fn newCtx |> ignore) false ) @@ -569,14 +553,13 @@ type WhenCmdBuilder() = member _.Run(build: BuildCmdInfo) = BuildStageIsActive(fun ctx -> let cmdInfo = - build.Invoke - { - // We should carefully procees the empty string in this build type - Name = CmdName.ShortName "" - Description = None - Values = [] - IsOptional = false - } + build.Invoke { + // We should carefully procees the empty string in this build type + Name = CmdName.ShortName "" + Description = None + Values = [] + IsOptional = false + } ctx.WhenCmdArg(cmdInfo) ) @@ -588,11 +571,10 @@ type WhenCmdBuilder() = /// Short name, long name [] member inline _.fullName([] build: BuildCmdInfo, shortName: string, longName: string) = - BuildCmdInfo(fun info -> - { build.Invoke(info) with + BuildCmdInfo(fun info -> { + build.Invoke(info) with Name = CmdName.FullName(shortName, longName) - } - ) + }) /// It is the same as shortName [] @@ -607,12 +589,13 @@ type WhenCmdBuilder() = member _.shortName(build: BuildCmdInfo, x: string) = BuildCmdInfo(fun info -> let info = build.Invoke(info) - { info with - Name = - match info.Name with - | CmdName.FullName(_, longName) - | CmdName.LongName longName when not (String.IsNullOrEmpty longName) -> CmdName.FullName(x, longName) - | _ -> CmdName.ShortName x + { + info with + Name = + match info.Name with + | CmdName.FullName(_, longName) + | CmdName.LongName longName when not (String.IsNullOrEmpty longName) -> CmdName.FullName(x, longName) + | _ -> CmdName.ShortName x } ) @@ -620,12 +603,13 @@ type WhenCmdBuilder() = member _.longName(build: BuildCmdInfo, x: string) = BuildCmdInfo(fun info -> let info = build.Invoke(info) - { info with - Name = - match info.Name with - | CmdName.FullName(shortName, _) - | CmdName.ShortName shortName when not (String.IsNullOrEmpty shortName) -> CmdName.FullName(shortName, x) - | _ -> CmdName.LongName x + { + info with + Name = + match info.Name with + | CmdName.FullName(shortName, _) + | CmdName.ShortName shortName when not (String.IsNullOrEmpty shortName) -> CmdName.FullName(shortName, x) + | _ -> CmdName.LongName x } ) @@ -650,14 +634,13 @@ type WhenEnvBuilder() = member _.Run(build: BuildEnvInfo) = BuildStageIsActive(fun ctx -> let arg = - build.Invoke - { - // We should carefully procees the empty string in this build type - Name = "" - Description = None - Values = [] - IsOptional = false - } + build.Invoke { + // We should carefully procees the empty string in this build type + Name = "" + Description = None + Values = [] + IsOptional = false + } ctx.WhenEnvArg(arg) ) diff --git a/Fun.Build/PipelineBuilder.fs b/Fun.Build/PipelineBuilder.fs index 6627b80..cc427c5 100644 --- a/Fun.Build/PipelineBuilder.fs +++ b/Fun.Build/PipelineBuilder.fs @@ -21,21 +21,20 @@ type PipelineBuilder(name: string) = member _.Run(build: BuildPipeline) = let ctx = build.Invoke(PipelineContext.Create name) - { ctx with - Stages = - ctx.Stages - |> List.map (fun x -> - { x with - ParentContext = ValueSome(StageParent.Pipeline ctx) - } - ) - PostStages = - ctx.PostStages - |> List.map (fun x -> - { x with - ParentContext = ValueSome(StageParent.Pipeline ctx) - } - ) + { + ctx with + Stages = + ctx.Stages + |> List.map (fun x -> { + x with + ParentContext = ValueSome(StageParent.Pipeline ctx) + }) + PostStages = + ctx.PostStages + |> List.map (fun x -> { + x with + ParentContext = ValueSome(StageParent.Pipeline ctx) + }) } @@ -70,11 +69,10 @@ type PipelineBuilder(name: string) = member inline _.Yield([] condition: BuildStageIsActive) = condition member inline _.Delay([] fn: unit -> BuildStageIsActive) = - BuildPipeline(fun ctx -> - { ctx with + BuildPipeline(fun ctx -> { + ctx with Verify = fun ctx -> fn().Invoke(ctx.MakeVerificationStage()) - } - ) + }) member inline _.Combine([] condition: BuildStageIsActive, [] build: BuildPipeline) = buildPipelineVerification build condition.Invoke @@ -104,8 +102,9 @@ type PipelineBuilder(name: string) = member inline _.timeout([] build: BuildPipeline, seconds: int) = BuildPipeline(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Timeout = ValueSome(TimeSpan.FromSeconds seconds) + { + ctx with + Timeout = ValueSome(TimeSpan.FromSeconds seconds) } ) @@ -123,8 +122,9 @@ type PipelineBuilder(name: string) = member inline _.timeoutForStage([] build: BuildPipeline, seconds: int) = BuildPipeline(fun ctx -> let ctx = build.Invoke ctx - { ctx with - TimeoutForStage = ValueSome(TimeSpan.FromSeconds seconds) + { + ctx with + TimeoutForStage = ValueSome(TimeSpan.FromSeconds seconds) } ) @@ -142,8 +142,9 @@ type PipelineBuilder(name: string) = member inline _.timeoutForStep([] build: BuildPipeline, seconds: int) = BuildPipeline(fun ctx -> let ctx = build.Invoke ctx - { ctx with - TimeoutForStep = ValueSome(TimeSpan.FromSeconds seconds) + { + ctx with + TimeoutForStep = ValueSome(TimeSpan.FromSeconds seconds) } ) @@ -161,8 +162,9 @@ type PipelineBuilder(name: string) = member inline _.envVars([] build: BuildPipeline, kvs: seq) = BuildPipeline(fun ctx -> let ctx = build.Invoke ctx - { ctx with - EnvVars = kvs |> Seq.fold (fun state (k, v) -> Map.add k v state) ctx.EnvVars + { + ctx with + EnvVars = kvs |> Seq.fold (fun state (k, v) -> Map.add k v state) ctx.EnvVars } ) @@ -183,9 +185,10 @@ type PipelineBuilder(name: string) = let argsInfo = resolveCmdArgsAndRemainings args - { ctx with - CmdArgs = argsInfo.CmdArgs - RemainingCmdArgs = argsInfo.RemainingArgs + { + ctx with + CmdArgs = argsInfo.CmdArgs + RemainingCmdArgs = argsInfo.RemainingArgs } ) @@ -278,11 +281,11 @@ type PipelineBuilder(name: string) = else args[index .. pipelineIndexes[i + 1] - 1] let argInfo = resolveCmdArgsAndRemainings args - let ctx = - { ctx with + let ctx = { + ctx with CmdArgs = argInfo.CmdArgs RemainingCmdArgs = argInfo.RemainingArgs - } + } if isHelp then ctx.RunCommandHelp(verbose) else ctx.Run() with | :? PipelineFailedException diff --git a/Fun.Build/PipelineContextExtensions.fs b/Fun.Build/PipelineContextExtensions.fs index 98141af..7c07bfd 100644 --- a/Fun.Build/PipelineContextExtensions.fs +++ b/Fun.Build/PipelineContextExtensions.fs @@ -56,10 +56,10 @@ module PipelineContextExtensionsInternal = | _ -> ValueNone - member this.MakeVerificationStage() = - { StageContext.Create("") with + member this.MakeVerificationStage() = { + StageContext.Create("") with ParentContext = ValueSome(StageParent.Pipeline this) - } + } member this.PrintError(msg: string) = @@ -75,11 +75,10 @@ module PipelineContextExtensionsInternal = let stages = stages - |> Seq.map (fun x -> - { x with + |> Seq.map (fun x -> { + x with ParentContext = ValueSome(StageParent.Pipeline this) - } - ) + }) |> Seq.toList let mutable i = 0 @@ -239,25 +238,25 @@ module PipelineContextExtensionsInternal = match step with | Step.StepFn _ -> () | Step.StepOfStage s -> - run - { s with + run { + s with ParentContext = ValueSome(StageParent.Stage stage) - } + } pipeline.Stages |> List.iter (fun stage -> - run - { stage with + run { + stage with ParentContext = ValueSome(StageParent.Pipeline pipeline) - } + } ) pipeline.PostStages |> List.iter (fun stage -> - run - { stage with + run { + stage with ParentContext = ValueSome(StageParent.Pipeline pipeline) - } + } ) if not verbose then @@ -299,15 +298,16 @@ module PipelineContextExtensionsInternal = let inline buildPipelineVerification ([] build: BuildPipeline) ([] conditionFn) = BuildPipeline(fun ctx -> let newCtx = build.Invoke ctx - { newCtx with - Verify = - fun ctx -> - match ctx.Mode with - | Mode.Execution -> newCtx.Verify ctx && conditionFn (ctx.MakeVerificationStage()) - | Mode.Verification - | Mode.CommandHelp _ -> - newCtx.Verify ctx |> ignore - conditionFn (ctx.MakeVerificationStage()) |> ignore - false + { + newCtx with + Verify = + fun ctx -> + match ctx.Mode with + | Mode.Execution -> newCtx.Verify ctx && conditionFn (ctx.MakeVerificationStage()) + | Mode.Verification + | Mode.CommandHelp _ -> + newCtx.Verify ctx |> ignore + conditionFn (ctx.MakeVerificationStage()) |> ignore + false } ) diff --git a/Fun.Build/ProcessExtensions.fs b/Fun.Build/ProcessExtensions.fs index e2b4b9e..339002e 100644 --- a/Fun.Build/ProcessExtensions.fs +++ b/Fun.Build/ProcessExtensions.fs @@ -101,14 +101,7 @@ type Process with static member StartAsync - ( - startInfo: ProcessStartInfo, - commandLogString: string, - logPrefix: string, - ?printOutput, - ?captureOutput, - ?cancellationToken: CancellationToken - ) = + (startInfo: ProcessStartInfo, commandLogString: string, logPrefix: string, ?printOutput, ?captureOutput, ?cancellationToken: CancellationToken) = async { let printOutput = defaultArg printOutput true let captureOutput = defaultArg captureOutput false @@ -163,10 +156,10 @@ type Process with Native.kill result ) :> IDisposable - | _ -> - { new IDisposable with + | _ -> { + new IDisposable with member _.Dispose() = () - } + } if shouldRedirectOutput then result.BeginOutputReadLine() diff --git a/Fun.Build/StageBuilder.fs b/Fun.Build/StageBuilder.fs index 762ff0c..7d5c40e 100644 --- a/Fun.Build/StageBuilder.fs +++ b/Fun.Build/StageBuilder.fs @@ -50,25 +50,25 @@ type StageBuilder(name: string) = member inline _.Yield([] builder: BuildStep) = builder member inline _.Delay([] fn: unit -> BuildStep) = - BuildStage(fun ctx -> - { ctx with + BuildStage(fun ctx -> { + ctx with Steps = ctx.Steps @ [ Step.StepFn(fn().Invoke) ] - } - ) + }) member inline _.Combine([] builder: BuildStep, [] build: BuildStage) = BuildStage(fun ctx -> - build.Invoke - { ctx with + build.Invoke { + ctx with Steps = ctx.Steps @ [ Step.StepFn builder.Invoke ] - } + } ) member inline _.For([] build: BuildStage, [] fn: unit -> BuildStep) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = ctx.Steps @ [ Step.StepFn(fn().Invoke) ] + { + ctx with + Steps = ctx.Steps @ [ Step.StepFn(fn().Invoke) ] } ) @@ -94,8 +94,9 @@ type StageBuilder(name: string) = member inline _.envVars([] build: BuildStage, kvs: seq) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - EnvVars = kvs |> Seq.fold (fun state (k, v) -> Map.add k v state) ctx.EnvVars + { + ctx with + EnvVars = kvs |> Seq.fold (fun state (k, v) -> Map.add k v state) ctx.EnvVars } ) @@ -158,9 +159,10 @@ type StageBuilder(name: string) = BuildStage(fun ctx -> let ctx = build.Invoke ctx let shouldContinue = defaultArg flag true - { ctx with - ContinueStepsOnFailure = shouldContinue - ContinueStageOnFailure = shouldContinue + { + ctx with + ContinueStepsOnFailure = shouldContinue + ContinueStageOnFailure = shouldContinue } ) @@ -171,8 +173,9 @@ type StageBuilder(name: string) = member inline _.timeout([] build: BuildStage, seconds: int) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Timeout = ValueSome(TimeSpan.FromSeconds seconds) + { + ctx with + Timeout = ValueSome(TimeSpan.FromSeconds seconds) } ) @@ -189,8 +192,9 @@ type StageBuilder(name: string) = member inline _.timeoutForStep([] build: BuildStage, seconds: int) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - TimeoutForStep = ValueSome(TimeSpan.FromSeconds seconds) + { + ctx with + TimeoutForStep = ValueSome(TimeSpan.FromSeconds seconds) } ) @@ -218,11 +222,10 @@ type StageBuilder(name: string) = /// Set if the steps in current stage should run in concurrent. Alias of paralle. [] member inline _.concurrent([] build: BuildStage, ?value: bool) = - BuildStage(fun ctx -> - { build.Invoke ctx with + BuildStage(fun ctx -> { + build.Invoke ctx with IsParallel = fun _ -> defaultArg value true - } - ) + }) /// Set workding dir for all steps under the stage. @@ -266,15 +269,16 @@ type StageBuilder(name: string) = member _.run(build: BuildStage, buildStep: StageContext -> BuildStep) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = - ctx.Steps - @ [ - Step.StepFn(fun (ctx, i) -> async { - let builder = buildStep ctx - return! builder.Invoke(ctx, i) - }) - ] + { + ctx with + Steps = + ctx.Steps + @ [ + Step.StepFn(fun (ctx, i) -> async { + let builder = buildStep ctx + return! builder.Invoke(ctx, i) + }) + ] } ) @@ -335,14 +339,15 @@ type StageBuilder(name: string) = member inline _.runSensitive([] build: BuildStage, command: FormattableString, ?cancellationToken: CancellationToken) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = - ctx.Steps - @ [ - Step.StepFn(fun (ctx, step) -> - ctx.RunSensitiveCommand(command, step, cancellationToken = defaultArg cancellationToken CancellationToken.None) - ) - ] + { + ctx with + Steps = + ctx.Steps + @ [ + Step.StepFn(fun (ctx, step) -> + ctx.RunSensitiveCommand(command, step, cancellationToken = defaultArg cancellationToken CancellationToken.None) + ) + ] } ) @@ -352,15 +357,16 @@ type StageBuilder(name: string) = member _.run(build: BuildStage, step: Async) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = - ctx.Steps - @ [ - Step.StepFn(fun _ -> async { - do! step - return Ok() - }) - ] + { + ctx with + Steps = + ctx.Steps + @ [ + Step.StepFn(fun _ -> async { + do! step + return Ok() + }) + ] } ) @@ -369,15 +375,16 @@ type StageBuilder(name: string) = member _.run(build: BuildStage, step: Async) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = - ctx.Steps - @ [ - Step.StepFn(fun (ctx, _) -> async { - let! exitCode = step - return ctx.MapExitCodeToResult exitCode - }) - ] + { + ctx with + Steps = + ctx.Steps + @ [ + Step.StepFn(fun (ctx, _) -> async { + let! exitCode = step + return ctx.MapExitCodeToResult exitCode + }) + ] } ) @@ -387,15 +394,16 @@ type StageBuilder(name: string) = member _.run(build: BuildStage, step: StageContext -> unit) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = - ctx.Steps - @ [ - Step.StepFn(fun (ctx, _) -> async { - step ctx - return Ok() - }) - ] + { + ctx with + Steps = + ctx.Steps + @ [ + Step.StepFn(fun (ctx, _) -> async { + step ctx + return Ok() + }) + ] } ) @@ -404,8 +412,9 @@ type StageBuilder(name: string) = member _.run(build: BuildStage, step: StageContext -> int) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = ctx.Steps @ [ Step.StepFn(fun (ctx, _) -> async { return ctx.MapExitCodeToResult(step ctx) }) ] + { + ctx with + Steps = ctx.Steps @ [ Step.StepFn(fun (ctx, _) -> async { return ctx.MapExitCodeToResult(step ctx) }) ] } ) @@ -415,15 +424,16 @@ type StageBuilder(name: string) = member _.run(build: BuildStage, step: StageContext -> Async) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = - ctx.Steps - @ [ - Step.StepFn(fun (ctx, _) -> async { - do! step ctx - return Ok() - }) - ] + { + ctx with + Steps = + ctx.Steps + @ [ + Step.StepFn(fun (ctx, _) -> async { + do! step ctx + return Ok() + }) + ] } ) @@ -432,15 +442,16 @@ type StageBuilder(name: string) = member _.run(build: BuildStage, step: StageContext -> Async) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = - ctx.Steps - @ [ - Step.StepFn(fun (ctx, _) -> async { - let! exitCode = step ctx - return ctx.MapExitCodeToResult exitCode - }) - ] + { + ctx with + Steps = + ctx.Steps + @ [ + Step.StepFn(fun (ctx, _) -> async { + let! exitCode = step ctx + return ctx.MapExitCodeToResult exitCode + }) + ] } ) @@ -450,8 +461,9 @@ type StageBuilder(name: string) = member _.run(build: BuildStage, step: StageContext -> Async>) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = ctx.Steps @ [ Step.StepFn(fun (ctx, _) -> step ctx) ] + { + ctx with + Steps = ctx.Steps @ [ Step.StepFn(fun (ctx, _) -> step ctx) ] } ) @@ -460,8 +472,9 @@ type StageBuilder(name: string) = member _.run(build: BuildStage, step: StageContext -> Task>) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = ctx.Steps @ [ Step.StepFn(fun (ctx, _) -> step ctx |> Async.AwaitTask) ] + { + ctx with + Steps = ctx.Steps @ [ Step.StepFn(fun (ctx, _) -> step ctx |> Async.AwaitTask) ] } ) @@ -470,8 +483,9 @@ type StageBuilder(name: string) = member _.run(build: BuildStage, step: StageContext -> Result) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = ctx.Steps @ [ Step.StepFn(fun (ctx, _) -> async { return step ctx }) ] + { + ctx with + Steps = ctx.Steps @ [ Step.StepFn(fun (ctx, _) -> async { return step ctx }) ] } ) @@ -481,15 +495,16 @@ type StageBuilder(name: string) = member _.run(build: BuildStage, step: StageContext -> Task) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = - ctx.Steps - @ [ - Step.StepFn(fun (ctx, _) -> async { - do! step ctx |> Async.AwaitTask - return Ok() - }) - ] + { + ctx with + Steps = + ctx.Steps + @ [ + Step.StepFn(fun (ctx, _) -> async { + do! step ctx |> Async.AwaitTask + return Ok() + }) + ] } ) @@ -498,15 +513,16 @@ type StageBuilder(name: string) = member _.run(build: BuildStage, step: StageContext -> Task) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = - ctx.Steps - @ [ - Step.StepFn(fun (ctx, _) -> async { - do! step ctx |> Async.AwaitTask - return Ok() - }) - ] + { + ctx with + Steps = + ctx.Steps + @ [ + Step.StepFn(fun (ctx, _) -> async { + do! step ctx |> Async.AwaitTask + return Ok() + }) + ] } ) @@ -515,15 +531,16 @@ type StageBuilder(name: string) = member _.run(build: BuildStage, step: StageContext -> Task) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = - ctx.Steps - @ [ - Step.StepFn(fun (ctx, _) -> async { - let! exitCode = step ctx |> Async.AwaitTask - return ctx.MapExitCodeToResult exitCode - }) - ] + { + ctx with + Steps = + ctx.Steps + @ [ + Step.StepFn(fun (ctx, _) -> async { + let! exitCode = step ctx |> Async.AwaitTask + return ctx.MapExitCodeToResult exitCode + }) + ] } ) @@ -533,18 +550,19 @@ type StageBuilder(name: string) = member _.runHttpHealthCheck(build: BuildStage, url: string, ?configRequest, ?cancellationToken) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = - ctx.Steps - @ [ - Step.StepFn(fun (ctx, _) -> - ctx.RunHttpHealthCheck( - url, - configRequest = defaultArg configRequest ignore, - cancellationToken = defaultArg cancellationToken CancellationToken.None + { + ctx with + Steps = + ctx.Steps + @ [ + Step.StepFn(fun (ctx, _) -> + ctx.RunHttpHealthCheck( + url, + configRequest = defaultArg configRequest ignore, + cancellationToken = defaultArg cancellationToken CancellationToken.None + ) ) - ) - ] + ] } ) @@ -554,18 +572,19 @@ type StageBuilder(name: string) = member inline _.echo([] build: BuildStage, msg: StageContext -> string) = BuildStage(fun ctx -> let ctx = build.Invoke ctx - { ctx with - Steps = - ctx.Steps - @ [ - Step.StepFn(fun (ctx, i) -> async { - if ctx.GetNoPrefixForStep() then - printfn "%s" (msg ctx) - else - printfn "%s %s" (ctx.BuildStepPrefix i) (msg ctx) - return Ok() - }) - ] + { + ctx with + Steps = + ctx.Steps + @ [ + Step.StepFn(fun (ctx, i) -> async { + if ctx.GetNoPrefixForStep() then + printfn "%s" (msg ctx) + else + printfn "%s %s" (ctx.BuildStepPrefix i) (msg ctx) + return Ok() + }) + ] } ) diff --git a/Fun.Build/StageContextExtensions.fs b/Fun.Build/StageContextExtensions.fs index 201c059..7d7d50c 100644 --- a/Fun.Build/StageContextExtensions.fs +++ b/Fun.Build/StageContextExtensions.fs @@ -170,13 +170,13 @@ module StageContextExtensionsInternal = if not isActive && stage.FailIfIgnored then let msg = $"Stage ({stage.GetNamePath()}) cannot be ignored (inactive)" AnsiConsole.MarkupLineInterpolated $"[red]{msg}[/]" - let verifyStage = - { stage with + let verifyStage = { + stage with ParentContext = match stage.ParentContext with | ValueSome(StageParent.Pipeline p) -> ValueSome(StageParent.Pipeline { p with Mode = Mode.Verification }) | x -> x - } + } stage.IsActive(verifyStage) |> ignore raise (PipelineFailedException msg) @@ -236,10 +236,10 @@ module StageContextExtensionsInternal = match step with | Step.StepFn _ -> stage.BuildStepPrefix(i) | Step.StepOfStage s -> - let subStage = - { s with + let subStage = { + s with ParentContext = ValueSome(StageParent.Stage stage) - } + } subStage.BuildCurrentStepPrefix() + ">" @@ -265,10 +265,10 @@ module StageContextExtensionsInternal = | Ok _ -> return true } | Step.StepOfStage subStage -> async { - let subStage = - { subStage with + let subStage = { + subStage with ParentContext = ValueSome(StageParent.Stage stage) - } + } let isSuccess, es = subStage.Run(StageIndex.Step i, linkedStepCTS.Token) exns.AddRange es return isSuccess @@ -375,8 +375,7 @@ module StageContextExtensionsInternal = ) | StageIndex.Stage i -> AnsiConsole.Write( - Rule($"""[grey50]STAGE #{i} [bold {color}]{namePath}[/] finished. {stageSW.ElapsedMilliseconds}ms.[/]""") - .LeftJustified() + Rule($"""[grey50]STAGE #{i} [bold {color}]{namePath}[/] finished. {stageSW.ElapsedMilliseconds}ms.[/]""").LeftJustified() ) | StageIndex.Step _ -> AnsiConsole.MarkupLineInterpolated( @@ -405,16 +404,17 @@ module StageContextExtensionsInternal = let inline buildStageIsActive ([] build: BuildStage) ([] conditionFn) = BuildStage(fun ctx -> let newCtx = build.Invoke ctx - { newCtx with - IsActive = - fun ctx -> - match ctx.GetMode() with - | Mode.Execution -> newCtx.IsActive ctx && conditionFn ctx - | Mode.Verification - | Mode.CommandHelp _ -> - newCtx.IsActive ctx |> ignore - conditionFn ctx |> ignore - false + { + newCtx with + IsActive = + fun ctx -> + match ctx.GetMode() with + | Mode.Execution -> newCtx.IsActive ctx && conditionFn ctx + | Mode.Verification + | Mode.CommandHelp _ -> + newCtx.IsActive ctx |> ignore + conditionFn ctx |> ignore + false } ) diff --git a/Fun.Build/Types.fs b/Fun.Build/Types.fs index 2de1ac4..d5cb1d1 100644 --- a/Fun.Build/Types.fs +++ b/Fun.Build/Types.fs @@ -34,13 +34,12 @@ type CmdName = | LongName x -> [ x ] | FullName(s, l) -> [ s; l ] -type CmdArg = - { - Name: CmdName - Values: string list - Description: string option - IsOptional: bool - } +type CmdArg = { + Name: CmdName + Values: string list + Description: string option + IsOptional: bool +} with static member Create(?shortName: string, ?longName: string, ?description: string, ?values, ?isOptional: bool) = { Name = @@ -60,13 +59,12 @@ type CmdArg = member this.WithOptional x = { this with IsOptional = x } -type EnvArg = - { - Name: string - Values: string list - Description: string option - IsOptional: bool - } +type EnvArg = { + Name: string + Values: string list + Description: string option + IsOptional: bool +} with static member Create(name: string, ?description: string, ?values, ?isOptional: bool) = { Name = name diff --git a/Fun.Build/Windows.fs b/Fun.Build/Windows.fs index 896bf58..0feb54c 100644 --- a/Fun.Build/Windows.fs +++ b/Fun.Build/Windows.fs @@ -12,33 +12,32 @@ module Windows = appName = EnvArg.Create("IIS_RECYCLE_APP_NAME") |} - let stage_deployToIIS (zippedPackageFile: string) = - stage "deploy to iis" { - whenEnvVar deployToIISOptions.host - whenEnvVar deployToIISOptions.user - whenEnvVar deployToIISOptions.pwd - whenEnvVar deployToIISOptions.siteName - whenEnvVar deployToIISOptions.targetDir - whenEnvVar deployToIISOptions.appName - run (fun ctx -> asyncResult { - let host = ctx.GetEnvVar deployToIISOptions.host.Name - let user = ctx.GetEnvVar deployToIISOptions.user.Name - let pwd = ctx.GetEnvVar deployToIISOptions.pwd.Name - let siteName = ctx.GetEnvVar deployToIISOptions.siteName.Name - let targetDir = ctx.GetEnvVar deployToIISOptions.targetDir.Name - let appName = ctx.GetEnvVar deployToIISOptions.appName.Name + let stage_deployToIIS (zippedPackageFile: string) = stage "deploy to iis" { + whenEnvVar deployToIISOptions.host + whenEnvVar deployToIISOptions.user + whenEnvVar deployToIISOptions.pwd + whenEnvVar deployToIISOptions.siteName + whenEnvVar deployToIISOptions.targetDir + whenEnvVar deployToIISOptions.appName + run (fun ctx -> asyncResult { + let host = ctx.GetEnvVar deployToIISOptions.host.Name + let user = ctx.GetEnvVar deployToIISOptions.user.Name + let pwd = ctx.GetEnvVar deployToIISOptions.pwd.Name + let siteName = ctx.GetEnvVar deployToIISOptions.siteName.Name + let targetDir = ctx.GetEnvVar deployToIISOptions.targetDir.Name + let appName = ctx.GetEnvVar deployToIISOptions.appName.Name - let msdeploy (x: string) = ctx.RunSensitiveCommand($"'C:/Program Files (x86)/IIS/Microsoft Web Deploy V3/msdeploy.exe' {x}") + let msdeploy (x: string) = ctx.RunSensitiveCommand($"'C:/Program Files (x86)/IIS/Microsoft Web Deploy V3/msdeploy.exe' {x}") - do! - msdeploy - $"-verb:sync -allowUntrusted -source:recycleApp -dest:recycleApp=\"{appName}\",recycleMode=\"StopAppPool\",computerName=\"{host}/msdeploy.axd?site={siteName}\",username=\"{user}\",password=\"{pwd}\",AuthType=\"Basic\"" + do! + msdeploy + $"-verb:sync -allowUntrusted -source:recycleApp -dest:recycleApp=\"{appName}\",recycleMode=\"StopAppPool\",computerName=\"{host}/msdeploy.axd?site={siteName}\",username=\"{user}\",password=\"{pwd}\",AuthType=\"Basic\"" - do! - msdeploy - $"-verb:sync -allowUntrusted -source:package=\"{zippedPackageFile}\" -dest:contentPath=\"{targetDir}\",computerName=\"{host}/msdeploy.axd?site={siteName}\",username=\"{user}\",password=\"{pwd}\",AuthType=\"Basic\" -enableRule:DoNotDeleteRule" - do! - msdeploy - $"-verb:sync -allowUntrusted -source:recycleApp -dest:recycleApp=\"{appName}\",recycleMode=\"StartAppPool\",computerName=\"{host}/msdeploy.axd?site={siteName}\",username=\"{user}\",password=\"{pwd}\",AuthType=\"Basic\"" - }) - } + do! + msdeploy + $"-verb:sync -allowUntrusted -source:package=\"{zippedPackageFile}\" -dest:contentPath=\"{targetDir}\",computerName=\"{host}/msdeploy.axd?site={siteName}\",username=\"{user}\",password=\"{pwd}\",AuthType=\"Basic\" -enableRule:DoNotDeleteRule" + do! + msdeploy + $"-verb:sync -allowUntrusted -source:recycleApp -dest:recycleApp=\"{appName}\",recycleMode=\"StartAppPool\",computerName=\"{host}/msdeploy.axd?site={siteName}\",username=\"{user}\",password=\"{pwd}\",AuthType=\"Basic\"" + }) + } diff --git a/build.fsx b/build.fsx index 3ba2c80..75b5e71 100644 --- a/build.fsx +++ b/build.fsx @@ -18,10 +18,10 @@ let stage_checkEnv = stage "Check environment" { run "dotnet tool restore" } let stage_lint = stage "Lint" { - stage "Format" { run "dotnet fantomas . -r" } + stage "Format" { run "dotnet fantomas" } stage "Check" { whenGithubAction - run "dotnet fantomas . -r --check" + run "dotnet fantomas check" } } diff --git a/demo.fsx b/demo.fsx index 9ba4b48..1cd1a25 100644 --- a/demo.fsx +++ b/demo.fsx @@ -21,10 +21,12 @@ let demo1 = run (fun ctx -> "dotnet --version") run (fun ctx -> async { return "dotnet --version" }) // You use use the RunCommand to run multiple command according to your logics - run (fun ctx -> asyncResult { - do! ctx.RunCommand "dotnet --version" - do! ctx.RunCommand "dotnet --version" - }) + run (fun ctx -> + asyncResult { + do! ctx.RunCommand "dotnet --version" + do! ctx.RunCommand "dotnet --version" + } + ) // You can run async functions run (Async.Sleep 1000) run (fun _ -> Async.Sleep 1000) @@ -106,9 +108,11 @@ pipeline "Fun.Build" { stage "Post stage" { echo "You are finished 😂" echo (fun ctx -> sprintf "You are finished here: %A" (ctx.GetWorkingDir())) - run (fun _ -> async { - return 0 // do something - }) + run (fun _ -> + async { + return 0 // do something + } + ) } ] // You can have multiple pipelines, sometimes you only want to run it only if the command specified the pipeline name. diff --git a/global.json b/global.json new file mode 100644 index 0000000..01cb658 --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "10.0.400", + "rollForward": "latestFeature" + } +}