diff --git a/Fun.Build.Tests/PipelineBuilderTests.fs b/Fun.Build.Tests/PipelineBuilderTests.fs index 52f893f..273c5a2 100644 --- a/Fun.Build.Tests/PipelineBuilderTests.fs +++ b/Fun.Build.Tests/PipelineBuilderTests.fs @@ -4,7 +4,6 @@ open Xunit open Fun.Build open System.Diagnostics open System.Threading.Tasks -open Xunit [] @@ -197,6 +196,36 @@ let ``runIfOnlySpecified should work`` () = } ) +[] +let ``runIfOnlySpecified should work for multiple -p`` () = + shouldBeCalled (fun call -> + let p1 = "demo1" + let p2 = "demo2" + let args = [ "-p"; p1; "d1"; "--"; "d1-1"; "-p"; p2; "d2"; "--"; "d2-2" ] + pipeline p1 { + cmdArgs args + stage "" { + run (fun ctx -> + call ctx + Assert.Equal([| "-p"; p1; "d1" |], ctx.GetAllCmdArgs()) + Assert.Equal([| "d1-1" |], ctx.GetRemainingCmdArgs()) + ) + } + runIfOnlySpecified + } + pipeline p2 { + cmdArgs args + stage "" { + run (fun ctx -> + call ctx + Assert.Equal([| "-p"; p2; "d2" |], ctx.GetAllCmdArgs()) + Assert.Equal([| "d2-2" |], ctx.GetRemainingCmdArgs()) + ) + } + runIfOnlySpecified + } + ) + [] let ``parallel should work`` () = diff --git a/Fun.Build/CHANGELOG.md b/Fun.Build/CHANGELOG.md index a6fa35a..fc38d50 100644 --- a/Fun.Build/CHANGELOG.md +++ b/Fun.Build/CHANGELOG.md @@ -2,6 +2,14 @@ ## [Unreleased] +## [1.1.17] - 2025-09-23 + +Support run multiple pipelines in one execution + +```bash +dotnet fsi build.fsx -- -p pipeline1 ... -p pipeline2 ... +``` + ## [1.1.16] - 2025-01-13 - Add optional argument disablePrintCommand diff --git a/Fun.Build/PipelineBuilder.fs b/Fun.Build/PipelineBuilder.fs index 655ca67..23b9b5c 100644 --- a/Fun.Build/PipelineBuilder.fs +++ b/Fun.Build/PipelineBuilder.fs @@ -11,6 +11,9 @@ type private IsSpecified = bool /// Used to keep registered data for later usage let private runIfOnlySpecifiedPipelines = System.Collections.Generic.List() +let private getPipelineIndexes args = + args |> Seq.indexed |> Seq.filter (fun (_, arg) -> arg = "-p" || arg = "--pipeline") |> Seq.map fst |> Seq.toList + type PipelineBuilder(name: string) = @@ -244,10 +247,15 @@ type PipelineBuilder(name: string) = let specified = defaultArg specified true let ctx = build.Invoke(PipelineContext.Create name) - let args = ctx.CmdArgs @ Array.toList (Environment.GetCommandLineArgs()) + let args = + if ctx.RemainingCmdArgs.IsEmpty then + ctx.CmdArgs + else + [ yield! ctx.CmdArgs; "--"; yield! ctx.RemainingCmdArgs ] + let isHelp = args |> Seq.exists (fun arg -> arg = "-h" || arg = "--help") let verbose = args |> Seq.exists (fun arg -> arg = "-v" || arg = "--verbose") - let pipelineIndex = args |> Seq.tryFindIndex (fun arg -> arg = "-p" || arg = "--pipeline") + let pipelineIndexes = getPipelineIndexes args runIfOnlySpecifiedPipelines.Add(specified, ctx) @@ -258,18 +266,24 @@ type PipelineBuilder(name: string) = ) try - if isHelp then - match pipelineIndex with - | Some index when List.length args > index + 1 && ctx.Name.Equals(args[index + 1], StringComparison.OrdinalIgnoreCase) -> - ctx.RunCommandHelp(verbose) - | _ -> () - else - match pipelineIndex with - | Some index when List.length args > index + 1 -> - if ctx.Name.Equals(args[index + 1], StringComparison.OrdinalIgnoreCase) then - ctx.Run() - | None when not specified -> ctx.Run() - | _ -> () + match pipelineIndexes with + | [] when not specified -> ctx.Run() + | [] -> () + | _ :: _ -> + for i, index in Seq.indexed pipelineIndexes do + if List.length args > index + 1 && ctx.Name.Equals(args[index + 1], StringComparison.OrdinalIgnoreCase) then + let args = + if i = Seq.length pipelineIndexes - 1 then + args[index..] + else + args[index .. pipelineIndexes[i + 1] - 1] + let argInfo = resolveCmdArgsAndRemainings args + let ctx = + { ctx with + CmdArgs = argInfo.CmdArgs + RemainingCmdArgs = argInfo.RemainingArgs + } + if isHelp then ctx.RunCommandHelp(verbose) else ctx.Run() with | :? PipelineFailedException | :? PipelineCancelledException -> @@ -287,17 +301,18 @@ let inline pipeline name = PipelineBuilder name /// If you only have one specified pipeline, it will try to print its command only help information. let tryPrintPipelineCommandHelp () = let args = Environment.GetCommandLineArgs() - let pipelineIndex = args |> Seq.tryFindIndex (fun arg -> arg = "-p" || arg = "--pipeline") - - match pipelineIndex with - | Some index -> - let pipelineName = args[index + 1] - let isPipelineRegistered = - runIfOnlySpecifiedPipelines - |> Seq.exists (fun struct (_, x) -> x.Name.Equals(pipelineName, StringComparison.OrdinalIgnoreCase)) - if not isPipelineRegistered then - AnsiConsole.MarkupLineInterpolated $"Pipeline [red]{pipelineName}[/] is not found." - AnsiConsole.MarkupLine "You can use [green]runIfOnlySpecified[/] for your pipline, or check if the name is correct." + let pipelineIndexes = getPipelineIndexes args + + match pipelineIndexes with + | _ :: _ -> + for index in pipelineIndexes do + let pipelineName = args[index + 1] + let isPipelineRegistered = + runIfOnlySpecifiedPipelines + |> Seq.exists (fun struct (_, x) -> x.Name.Equals(pipelineName, StringComparison.OrdinalIgnoreCase)) + if not isPipelineRegistered then + AnsiConsole.MarkupLineInterpolated $"Pipeline [red]{pipelineName}[/] is not found." + AnsiConsole.MarkupLine "You can use [green]runIfOnlySpecified[/] for your pipline, or check if the name is correct." | _ -> let isHelp = args |> Seq.exists (fun arg -> arg = "-h" || arg = "--help") diff --git a/demo-cmd.fsx b/demo-cmd.fsx index a7f338a..b5abe14 100644 --- a/demo-cmd.fsx +++ b/demo-cmd.fsx @@ -12,11 +12,10 @@ module Apps = let all = [ app1; app2; app3 ] -let args = {| - app = fun apps -> CmdArg.Create(shortName = "-a", longName = "--app", values = apps, description = "specify the app you want to dev") - path = CmdArg.Create("-f", "--file", "publish directory for the app") - watch = CmdArg.Create(shortName = "-w", description = "if is in watch mode") -|} +let args = + {| app = fun apps -> CmdArg.Create(shortName = "-a", longName = "--app", values = apps, description = "specify the app you want to dev") + path = CmdArg.Create("-f", "--file", "publish directory for the app") + watch = CmdArg.Create(shortName = "-w", description = "if is in watch mode") |} pipeline "demo" { @@ -64,4 +63,12 @@ pipeline "demo" { runIfOnlySpecified } + +pipeline "demo2" { + description "another demo" + stage "build" { echo "build something" } + runIfOnlySpecified +} + + tryPrintPipelineCommandHelp ()