diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 0e8de9c..25c3fa0 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -21,4 +21,4 @@ jobs: with: dotnet-version: 6.0.x - name: Run CI - run: dotnet fsi src/build.fsx + run: dotnet fsi src\build.fsx -- test diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index ed168c4..e7b9e72 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,6 +10,18 @@ name: Publish to NuGet on: workflow_dispatch: + # push is unsuccessful if attempts to push same package anyway + push: + branches: main + # The pack/push stage is only run ON the main branch. Otherwise it will finish at + # test. + pull_request: + # never run on a pull request that changes the build script or the CI - security concern + paths-ignore: + - '**/*/build.fsx' + - '**/*/publish.yml' + branches: + - main jobs: publish: @@ -27,12 +39,6 @@ jobs: with: dotnet-version: 6.0.x - - name: Test - run: dotnet test src/Tests/Tests.fsproj --configuration Release - - - name: Pack - run: dotnet pack src/FSharp.SystemCommandLine/FSharp.SystemCommandLine.fsproj --configuration Release --output artifacts - - name: NuGet login (OIDC -> temp API key) uses: NuGet/login@v1 id: login @@ -40,5 +46,4 @@ jobs: user: "jordan marr" # nuget.org profile name (not email) - name: Push - # Backslash separator is required: on Windows, dotnet nuget push only expands wildcards in paths using '\' - run: dotnet nuget push artifacts\*.nupkg --api-key ${{ steps.login.outputs.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate + run: dotnet fsi src\build.fsx -- publish --nuget-key ${{ steps.login.outputs.NUGET_API_KEY }} diff --git a/src/build.fsx b/src/build.fsx index 460f9f5..5021702 100644 --- a/src/build.fsx +++ b/src/build.fsx @@ -1,42 +1,133 @@ -#r "nuget: Fun.Build, 1.1.17" +#r "nuget: Partas.Build" +#r "nuget: Partas.TypeProvider.BuildHelper" -open Fun.Build +#nowarn 3886 -let src = __SOURCE_DIRECTORY__ -let fsproj = $"{src}/FSharp.SystemCommandLine/FSharp.SystemCommandLine.fsproj" +open Partas.Build +open Partas.TypeProvider.BuildHelper -pipeline "Build" { +[] +let root = __SOURCE_DIRECTORY__ + "\\.." - stage "Build FSharp.SystemCommandLine.sln" { - run $"dotnet restore {fsproj}" - run $"dotnet build {fsproj} --configuration Release" - } +type Repo = BuildHelperProvider + +// command line options +module Options = + let quick = + Input.option "--quick" + |> Input.def false + |> Input.desc "Skip restore/clean etc" + let config = + Baked.Input.DotNet.configString + |> InputSpec.ofInput + |> InputSpec.map (Option.defaultValue "Release") + let skipTests = + Input.option "--skip-tests" + |> Input.def false + |> Input.desc "Skip tests" + // aliases for our projects + let projectMap = Map.ofList [ + "fs-scl", Repo.Project.``FSharp.SystemCommandLine``.Path + ] + // useful if adding extra projects to the solution + let target = + Input.option "--project" + |> Input.alias "-p" + |> Input.desc "Target specific project(s)" + |> Input.arity OneOrMore + |> Input.allowMultipleArgumentsPerToken + |> Input.def [ "fs-scl" ] + |> Input.acceptOnlyFromAmong (projectMap |> Map.keys |> Seq.toList) + |> InputSpec.ofInput + |> InputSpec.map (List.map (fun project -> projectMap[project])) - stage "Run Tests" { - run $"dotnet test {src}/Tests/Tests.fsproj --configuration Release" +// start defining common actions +let restore = input { + let! quick = Options.quick + return stage "restore" { + quiet + when' (not quick) + run $"dotnet restore {Repo.FileSystem.src.``FSharp.SystemCommandLine.sln``.FullName}" } - - runIfOnlySpecified false } -open System.Xml.Linq - -pipeline "Publish" { +let build = input { + let! config = Options.config + // could make this target projects if we wanted + and! target = Options.target + return stage "build" { + quiet + parallel' + for project in target do + stage $"build {project}" { + run $"dotnet build {project} --configuration {config}" + } + } +} - stage "Pack" { - run $"dotnet pack {fsproj} --configuration Release" +let pack = input { + let! config = Options.config + and! target = Options.target + return stage "pack" { + quiet + whenBranch "main" + for project in target do + stage $"pack {project}" { + run $"dotnet pack {project} --configuration {config} --no-build --no-restore -o {Repo.VirtualFileSystem.artifacts.ToString()}" + } } +} - stage "Push to NuGet" { - run (fun _ -> - let version = XDocument.Load(fsproj).Descendants(XName.Get "Version") |> Seq.head |> _.Value - let nupkg = $"{src}/FSharp.SystemCommandLine/bin/Release/FSharp.SystemCommandLine.%s{version}.nupkg" - let nugetKey = System.Environment.GetEnvironmentVariable("NUGET_KEY") - $"dotnet nuget push %s{nupkg} --source https://api.nuget.org/v3/index.json --api-key %s{nugetKey} --skip-duplicate" - ) +let test = input { + let! skipTests = Options.skipTests + and! config = Options.config + and! ci = Baked.Input.CI.isCI + return stage "test" { + quiet + when' (not skipTests) + outputTo ( + if ci + then StageOutput.Silent + else StageOutput.Console + ) + run $"dotnet test {Repo.Project.Tests.Path} --configuration {config}" } +} - runIfOnlySpecified true +let push = input { + let! apiKey = Baked.Input.NuGet.apiKeyOrEnv |> Input.required + let pushPath = System.IO.Path.Combine(Repo.VirtualFileSystem.artifacts.ToString(), "*.nupkg") + return stage "push" { + when' apiKey.IsSome + whenBranch "main" + run $"dotnet nuget push {pushPath} --api-key {Cmd.secret apiKey.Value} --source https://api.nuget.org/v3/index.json --skip-duplicate" + } } -tryPrintPipelineCommandHelp () \ No newline at end of file +let bump = Baked.Pipelines.bumpArgument (Options.projectMap.Values |> Seq.toList) Options.target + +rootCommand fsi.CommandLineArgs[1..] { + description "Build script for FSharp.SystemCommandLine" + command "bump" { + description "Bump version numbers. Will fail if performed in CI. Do local, then commit, then push." + bump + } + command "build" { + description "Builds the solution" + restore + build + } + command "test" { + description "Runs the tests" + restore + test + } + command "publish" { + description "Publishes the packages" + restore + build + test + pack + push + } +} \ No newline at end of file diff --git a/src/publish.bat b/src/publish.bat deleted file mode 100644 index b5010f6..0000000 --- a/src/publish.bat +++ /dev/null @@ -1 +0,0 @@ -dotnet fsi build.fsx -- -p Build -p Publish