Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion Fun.Build.Tests/PipelineBuilderTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ open Xunit
open Fun.Build
open System.Diagnostics
open System.Threading.Tasks
open Xunit


[<Fact>]
Expand Down Expand Up @@ -197,6 +196,36 @@ let ``runIfOnlySpecified should work`` () =
}
)

[<Fact>]
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
}
)


[<Fact>]
let ``parallel should work`` () =
Expand Down
8 changes: 8 additions & 0 deletions Fun.Build/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
65 changes: 40 additions & 25 deletions Fun.Build/PipelineBuilder.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ type private IsSpecified = bool
/// Used to keep registered data for later usage
let private runIfOnlySpecifiedPipelines = System.Collections.Generic.List<struct (IsSpecified * PipelineContext)>()

let private getPipelineIndexes args =
args |> Seq.indexed |> Seq.filter (fun (_, arg) -> arg = "-p" || arg = "--pipeline") |> Seq.map fst |> Seq.toList


type PipelineBuilder(name: string) =

Expand Down Expand Up @@ -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)

Expand All @@ -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 ->
Expand All @@ -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")
Expand Down
17 changes: 12 additions & 5 deletions demo-cmd.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
Expand Down Expand Up @@ -64,4 +63,12 @@ pipeline "demo" {
runIfOnlySpecified
}


pipeline "demo2" {
description "another demo"
stage "build" { echo "build something" }
runIfOnlySpecified
}


tryPrintPipelineCommandHelp ()
Loading