// -------------------------------------------------------------------------------------- // FAKE build script // -------------------------------------------------------------------------------------- #r @"packages/build/FAKE/tools/FakeLib.dll" open Fake open Fake.Git open Fake.AssemblyInfoFile open Fake.ReleaseNotesHelper open Fake.UserInputHelper open System open System.IO open System.Diagnostics // -------------------------------------------------------------------------------------- // START TODO: Provide project-specific details below // -------------------------------------------------------------------------------------- // Information about the project are used // - for version and project name in generated AssemblyInfo file // - by the generated NuGet package // - to run tests and to publish documentation on GitHub gh-pages // - for documentation, you also need to edit info in "docsrc/tools/generate.fsx" // The name of the project // (used by attributes in AssemblyInfo, name of a NuGet package and directory in 'src') let project = "LogicalHacking.ExtensionDsLab" // Short summary of the project // (used as description in AssemblyInfo and as a short summary for NuGet package) let summary = "A data science framework for analyzing Chrome browser extensions." // Longer description of the project // (used as a description for NuGet package; line breaks are automatically cleaned up) let description = "A data science framework for analyzing Chrome browser extensions." // List of author names (for NuGet package) let authors = [ "Achim D. Brucker" ] // Tags for your project (for NuGet package) let tags = "ChromeExtension DataScience BrowserSecurity" // File system information let solutionFile = "LogicalHacking.ExtensionDsLab.sln" // Default target configuration let configuration = "Release" // Pattern specifying assemblies to be tested using NUnit let testAssemblies = "tests/**/bin" configuration "*Tests*.dll" // Git configuration (used for publishing documentation in gh-pages branch) // The profile where the project is posted let gitOwner = "BrowserSecurity" let gitHome = sprintf "%s/%s" "https://git.logicalhacking.com" gitOwner // The name of the project on GitHub let gitName = "ExtensionDsLab" // The url for the raw files hosted let gitRaw = environVarOrDefault "gitRaw" "https://git.logicalhacking.com/BrowserSecurity" // -------------------------------------------------------------------------------------- // END TODO: The rest of the file includes standard build steps // -------------------------------------------------------------------------------------- // Read additional information from the release notes document let release = LoadReleaseNotes "RELEASE_NOTES.md" // Helper active pattern for project types let (|Fsproj|Csproj|Vbproj|Shproj|) (projFileName:string) = match projFileName with | f when f.EndsWith("fsproj") -> Fsproj | f when f.EndsWith("csproj") -> Csproj | f when f.EndsWith("vbproj") -> Vbproj | f when f.EndsWith("shproj") -> Shproj | _ -> failwith (sprintf "Project file %s not supported. Unknown project type." projFileName) // Generate assembly info files with the right version & up-to-date information Target "AssemblyInfo" (fun _ -> let getAssemblyInfoAttributes projectName = [ Attribute.Title (projectName) Attribute.Product project Attribute.Description summary Attribute.Version release.AssemblyVersion Attribute.FileVersion release.AssemblyVersion Attribute.Configuration configuration ] let getProjectDetails projectPath = let projectName = System.IO.Path.GetFileNameWithoutExtension(projectPath) ( projectPath, projectName, System.IO.Path.GetDirectoryName(projectPath), (getAssemblyInfoAttributes projectName) ) !! "src/**/*.??proj" |> Seq.map getProjectDetails |> Seq.iter (fun (projFileName, projectName, folderName, attributes) -> match projFileName with | Fsproj -> CreateFSharpAssemblyInfo (folderName "AssemblyInfo.fs") attributes | Csproj -> CreateCSharpAssemblyInfo ((folderName "Properties") "AssemblyInfo.cs") attributes | Vbproj -> CreateVisualBasicAssemblyInfo ((folderName "My Project") "AssemblyInfo.vb") attributes | Shproj -> () ) ) // Copies binaries from default VS location to expected bin folder // But keeps a subdirectory structure for each project in the // src folder to support multiple project outputs Target "CopyBinaries" (fun _ -> !! "src/**/*.??proj" -- "src/**/*.shproj" |> Seq.map (fun f -> ((System.IO.Path.GetDirectoryName f) "bin" configuration, "bin" (System.IO.Path.GetFileNameWithoutExtension f))) |> Seq.iter (fun (fromDir, toDir) -> CopyDir toDir fromDir (fun _ -> true)) ) // -------------------------------------------------------------------------------------- // Clean build results let vsProjProps = #if MONO [ ("DefineConstants","MONO"); ("Configuration", configuration) ] #else [ ("Configuration", configuration); ("Platform", "Any CPU") ] #endif Target "Clean" (fun _ -> !! solutionFile |> MSBuildReleaseExt "" vsProjProps "Clean" |> ignore CleanDirs ["bin"; "temp"; "docs"] ) // -------------------------------------------------------------------------------------- // Build library & test project Target "Build" (fun _ -> !! solutionFile |> MSBuildReleaseExt "" vsProjProps "Rebuild" |> ignore ) // -------------------------------------------------------------------------------------- // Run the unit tests using test runner Target "RunTests" (fun _ -> !! testAssemblies |> NUnit (fun p -> { p with DisableShadowCopy = true TimeOut = TimeSpan.FromMinutes 20. OutputFile = "TestResults.xml" }) ) // -------------------------------------------------------------------------------------- // Build a NuGet package Target "NuGet" (fun _ -> Paket.Pack(fun p -> { p with OutputPath = "bin" Version = release.NugetVersion ReleaseNotes = toLines release.Notes}) ) Target "PublishNuget" (fun _ -> Paket.Push(fun p -> { p with PublishUrl = "https://www.nuget.org" WorkingDir = "bin" }) ) // -------------------------------------------------------------------------------------- // Generate the documentation let fakePath = "packages" "build" "FAKE" "tools" "FAKE.exe" let fakeStartInfo script workingDirectory args fsiargs environmentVars = (fun (info: ProcessStartInfo) -> info.FileName <- System.IO.Path.GetFullPath fakePath info.Arguments <- sprintf "%s --fsiargs -d:FAKE %s \"%s\"" args fsiargs script info.WorkingDirectory <- workingDirectory let setVar k v = info.EnvironmentVariables.[k] <- v for (k, v) in environmentVars do setVar k v setVar "MSBuild" msBuildExe setVar "GIT" Git.CommandHelper.gitPath setVar "FSI" fsiPath) /// Run the given buildscript with FAKE.exe let executeFAKEWithOutput workingDirectory script fsiargs envArgs = let exitCode = ExecProcessWithLambdas (fakeStartInfo script workingDirectory "" fsiargs envArgs) TimeSpan.MaxValue false ignore ignore System.Threading.Thread.Sleep 1000 exitCode // Documentation let buildDocumentationTarget fsiargs target = trace (sprintf "Building documentation (%s), this could take some time, please wait..." target) let exit = executeFAKEWithOutput "docsrc/tools" "generate.fsx" fsiargs ["target", target] if exit <> 0 then failwith "generating reference documentation failed" () Target "GenerateReferenceDocs" (fun _ -> buildDocumentationTarget "-d:RELEASE -d:REFERENCE" "Default" ) let generateHelp' fail debug = let args = if debug then "--define:HELP" else "--define:RELEASE --define:HELP" try buildDocumentationTarget args "Default" traceImportant "Help generated" with | e when not fail -> traceImportant "generating help documentation failed" let generateHelp fail = generateHelp' fail false Target "GenerateHelp" (fun _ -> DeleteFile "docsrc/content/release-notes.md" CopyFile "docsrc/content/" "RELEASE_NOTES.md" Rename "docsrc/content/release-notes.md" "docsrc/content/RELEASE_NOTES.md" DeleteFile "docsrc/content/license.md" CopyFile "docsrc/content/" "LICENSE" Rename "docsrc/content/license.md" "docsrc/content/LICENSE" generateHelp true ) Target "GenerateHelpDebug" (fun _ -> DeleteFile "docsrc/content/release-notes.md" CopyFile "docsrc/content/" "RELEASE_NOTES.md" Rename "docsrc/content/release-notes.md" "docsrc/content/RELEASE_NOTES.md" DeleteFile "docsrc/content/license.md" CopyFile "docsrc/content/" "LICENSE" Rename "docsrc/content/license.md" "docsrc/content/LICENSE" generateHelp' true true ) Target "KeepRunning" (fun _ -> use watcher = !! "docsrc/content/**/*.*" |> WatchChanges (fun changes -> generateHelp' true true ) traceImportant "Waiting for help edits. Press any key to stop." System.Console.ReadKey() |> ignore watcher.Dispose() ) Target "GenerateDocs" DoNothing let createIndexFsx lang = let content = """(*** hide ***) // This block of code is omitted in the generated HTML documentation. Use // it to define helpers that you do not want to show in the documentation. #I "../../../bin" (** F# Project Scaffold ({0}) ========================= *) """ let targetDir = "docsrc/content" lang let targetFile = targetDir "index.fsx" ensureDirectory targetDir System.IO.File.WriteAllText(targetFile, System.String.Format(content, lang)) Target "AddLangDocs" (fun _ -> let args = System.Environment.GetCommandLineArgs() if args.Length < 4 then failwith "Language not specified." args.[3..] |> Seq.iter (fun lang -> if lang.Length <> 2 && lang.Length <> 3 then failwithf "Language must be 2 or 3 characters (ex. 'de', 'fr', 'ja', 'gsw', etc.): %s" lang let templateFileName = "template.cshtml" let templateDir = "docsrc/tools/templates" let langTemplateDir = templateDir lang let langTemplateFileName = langTemplateDir templateFileName if System.IO.File.Exists(langTemplateFileName) then failwithf "Documents for specified language '%s' have already been added." lang ensureDirectory langTemplateDir Copy langTemplateDir [ templateDir templateFileName ] createIndexFsx lang) ) // -------------------------------------------------------------------------------------- // Release Scripts #load "paket-files/build/fsharp/FAKE/modules/Octokit/Octokit.fsx" open Octokit Target "Release" (fun _ -> let user = match getBuildParam "github-user" with | s when not (String.IsNullOrWhiteSpace s) -> s | _ -> getUserInput "Username: " let pw = match getBuildParam "github-pw" with | s when not (String.IsNullOrWhiteSpace s) -> s | _ -> getUserPassword "Password: " let remote = Git.CommandHelper.getGitResult "" "remote -v" |> Seq.filter (fun (s: string) -> s.EndsWith("(push)")) |> Seq.tryFind (fun (s: string) -> s.Contains(gitOwner + "/" + gitName)) |> function None -> gitHome + "/" + gitName | Some (s: string) -> s.Split().[0] StageAll "" Git.Commit.Commit "" (sprintf "Bump version to %s" release.NugetVersion) Branches.pushBranch "" remote (Information.getBranchName "") Branches.tag "" release.NugetVersion Branches.pushTag "" remote release.NugetVersion // release on github createClient user pw |> createDraft gitOwner gitName release.NugetVersion (release.SemVer.PreRelease <> None) release.Notes // TODO: |> uploadFile "PATH_TO_FILE" |> releaseDraft |> Async.RunSynchronously ) Target "BuildPackage" DoNothing // -------------------------------------------------------------------------------------- // Run all targets by default. Invoke 'build ' to override Target "All" DoNothing "AssemblyInfo" ==> "Build" ==> "CopyBinaries" ==> "RunTests" ==> "GenerateReferenceDocs" ==> "GenerateDocs" ==> "NuGet" ==> "BuildPackage" ==> "All" "GenerateHelp" ==> "GenerateReferenceDocs" ==> "GenerateDocs" "GenerateHelpDebug" ==> "KeepRunning" "Clean" ==> "Release" "BuildPackage" ==> "PublishNuget" ==> "Release" RunTargetOrDefault "All"