build/scripts/Commandline.fs (258 lines of code) (raw):

// Licensed to Elasticsearch B.V under one or more agreements. // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. namespace Scripts open System open System.Runtime.InteropServices open Fake.Core open Fake.IO open Octokit //this is ugly but a direct port of what used to be duplicated in our DOS and bash scripts module Commandline = let private usage = """ USAGE: build <target> [params] [skiptests] Targets: * build-all - default target if non provided. Performs rebuild and tests all TFM's * clean - cleans build output folders * test [testfilter] - incremental build and unit test for .NET 4.5, [testfilter] allows you to do a contains match on the tests to be run. * release <version> - 0 create a release worthy nuget packages for [version] under build\output * integrate <elasticsearch_versions> [clustername] [testfilter] - run integration tests for <elasticsearch_versions> which is a semicolon separated list of elasticsearch versions to test or `latest`. Can filter tests by <clustername> and <testfilter> * canary - create a canary nuget package based on the current version. * cluster <cluster-name> [version] - Start a cluster defined in Tests.Core or Tests from the command line and leaves it running untill a key is pressed. Handy if you want to run the integration tests numerous times while developing * benchmark [non-interactive] [url] [username] [password] - Runs a benchmark from Tests.Benchmarking and indexes the results to [url] when provided. If non-interactive runs all benchmarks without prompting * codegen <branch> [arguments] - runs the code generator, the first argument is required and dictates the branch to sync from. - Any other arguments are passed down to the tool directly * documentation - runs the doc generation, without running any tests NOTE: both the `test` and `integrate` targets can be suffixed with `-all` to force the tests against all suported TFM's Execution hints can be provided anywhere on the command line - skiptests : skip running tests as part of the target chain - gendocs : generate documentation - non-interactive : make targets that run in interactive mode by default to run unassisted. - docs:<B> : the branch name B to use when generating documentation - ref:<B> : the reference version B to use when generating documentation - seed:<N> : provide a seed to run the tests with. - random:<K><:B> : sets random K to bool B if if B is omitted will default to true K can be: sourceserializer, typedkeys or oldconnection (only valid on windows) """ let private (|IsUrl|_|) (candidate:string) = match Uri.TryCreate(candidate, UriKind.RelativeOrAbsolute) with | true, _ -> Some candidate | _ -> None let private (|IsDiff|_|) (candidate:string) = let c = candidate.ToLowerInvariant() match c with | "github" | "nuget" | "directories" | "assemblies" -> Some c | _ -> failwith (sprintf "Unknown diff type: %s" candidate) let private (|IsProject|_|) (candidate:string) = let c = candidate.ToLowerInvariant() match c with | "elastic.clients.elasticsearch" | "elastic.clients.elasticsearch.jsonnetserializer" -> Some c | _ -> None let private (|IsFormat|_|) (candidate:string) = let c = candidate.ToLowerInvariant() match c with | "xml" | "markdown" | "asciidoc" -> Some c | _ -> None type MultiTarget = All | One type VersionArguments = { Version: string; OutputLocation: string option } type TestArguments = { TrxExport: bool; TestFilter: string option; } type IntegrationArguments = { TrxExport: bool; TestFilter: string option; ClusterFilter: string option; ElasticsearchVersions: string list; } type BenchmarkArguments = { Endpoint: string; Username: string option; Password: string option; } type ClusterArguments = { Name: string; Version: string option; } type CodeGenArguments = { Branch: string; } type CommandArguments = | Unknown | SetVersion of VersionArguments | Test of TestArguments | Integration of IntegrationArguments | Benchmark of BenchmarkArguments | Cluster of ClusterArguments | CodeGen of CodeGenArguments type PassedArguments = { NonInteractive: bool; SkipTests: bool; SkipReleaseNotes: bool; GenDocs: bool; Seed: int; RandomArguments: string list; DocsBranch: string; ReferenceBranch: string; RemainingArguments: string list; MultiTarget: MultiTarget ReleaseBuild: bool; Target: string; CommandArguments: CommandArguments; } let notWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX) let parse (args: string list) = let filteredArgs = args |> List.filter(fun x -> x <> "--report" && x <> "skiptests" && x <> "gendocs" && x <> "skipdocs" && x <> "skip-release-notes" && x <> "non-interactive" && not (x.StartsWith("seed:")) && not (x.StartsWith("random:")) && not (x.StartsWith("docs:")) && not (x.StartsWith("ref:"))) |> List.map(fun (s:string) -> let containsSpace = s.Contains(" ") match s with | x when containsSpace -> sprintf "\"%s\"" x | s -> s ) let target = match (filteredArgs |> List.tryHead) with | Some t -> t.Replace("-one", "") | _ -> "build" let skipTests = args |> List.exists (fun x -> x = "skiptests") || target = "documentation" let skipDocs = args |> List.exists (fun x -> x = "skipdocs") let report = args |> List.exists (fun x -> x = "--report") printf "%b exist" report let parsed = { NonInteractive = args |> List.exists (fun x -> x = "non-interactive") SkipTests = skipTests SkipReleaseNotes = skipTests GenDocs = not skipDocs && (args |> List.exists (fun x -> x = "gendocs") || target = "build" || target = "documentation") Seed = match args |> List.tryFind (fun x -> x.StartsWith("seed:")) with | Some t -> Int32.Parse (t.Replace("seed:", "")) | _ -> Random().Next(1, 100_000) RandomArguments = args |> List.filter (fun x -> (x.StartsWith("random:"))) |> List.map (fun x -> (x.Replace("random:", ""))) DocsBranch = match args |> List.tryFind (fun x -> x.StartsWith("docs:")) with | Some t -> t.Replace("docs:", "") | _ -> "" ReferenceBranch = match args |> List.tryFind (fun x -> x.StartsWith("ref:")) with | Some t -> t.Replace("ref:", "") | _ -> "" RemainingArguments = filteredArgs MultiTarget = match (filteredArgs |> List.tryHead) with | Some t when t.EndsWith("-one") -> MultiTarget.One | _ -> MultiTarget.All Target = match (filteredArgs |> List.tryHead) with | Some t -> t.Replace("-one", "") | _ -> "build" ReleaseBuild = match target with | "canary" | "release" -> true | _ -> false CommandArguments = Unknown } let arguments = match filteredArgs with | _ :: tail -> target :: tail | [] -> [target] let split (s:string) = s.Split ',' |> Array.toList match arguments with | [] | ["build"] | ["clean"] | ["benchmark"] | ["documentation"; ] | ["profile"] -> parsed | "rest-spec-tests" :: tail -> { parsed with RemainingArguments = tail } | "codegen" :: branch :: tail -> { parsed with CommandArguments = CodeGen { Branch = branch }; RemainingArguments = tail } | ["set-version"; version] -> { parsed with CommandArguments = SetVersion { Version = version; OutputLocation = None }; } | ["release"; version] -> { parsed with CommandArguments = SetVersion { Version = version; OutputLocation = None }; } | ["release"; version; path] -> if (not <| System.IO.Directory.Exists path) then failwithf "'%s' is not an existing directory" (Path.getFullName path) { parsed with CommandArguments = SetVersion { Version = version; OutputLocation = Some path }; } | ["canary"] -> { parsed with CommandArguments = Test { TestFilter = None TrxExport = report } } | ["test"] -> { parsed with CommandArguments = Test { TestFilter = None TrxExport = report } } | ["test"; testFilter] -> { parsed with CommandArguments = Test { TestFilter = Some testFilter TrxExport = report } } | ["benchmark"; IsUrl elasticsearch; username; password] -> { parsed with CommandArguments = Benchmark { Endpoint = elasticsearch; Username = Some username; Password = Some password; } } | ["benchmark"; IsUrl elasticsearch] -> { parsed with CommandArguments = Benchmark { Endpoint = elasticsearch; Username = None Password = None } } | ["integrate"; esVersions] -> { parsed with CommandArguments = Integration { TrxExport = report ElasticsearchVersions = split esVersions; ClusterFilter = None; TestFilter = None } } | ["integrate"; esVersions; clusterFilter] -> { parsed with CommandArguments = Integration { TrxExport = report ElasticsearchVersions = split esVersions; ClusterFilter = Some clusterFilter; TestFilter = None } } | ["integrate"; esVersions; clusterFilter; testFilter] -> { parsed with CommandArguments = Integration { TrxExport = report ElasticsearchVersions = split esVersions; ClusterFilter = Some clusterFilter TestFilter = Some testFilter } } | ["cluster"; clusterName] -> { parsed with CommandArguments = Cluster { Name = clusterName; Version = None } } | ["cluster"; clusterName; clusterVersion] -> { parsed with CommandArguments = Cluster { Name = clusterName; Version = Some clusterVersion } } | _ -> eprintf "%s" usage failwith "Please consult printed help text on how to call our build"