diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 3e68fba968..ae19f9b0e6 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -4,32 +4,115 @@ on:
pull_request:
push:
+permissions: write-all
+
jobs:
- build-windows:
+
+ build-windows-core:
+ runs-on: windows-latest
+ steps:
+ - name: Disable Windows Defender
+ run: Set-MpPreference -DisableRealtimeMonitoring $true
+ shell: powershell
+ - uses: actions/checkout@v3
+ - name: Run task 'Build'
+ shell: cmd
+ run: |
+ call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
+ ./build.cmd Build
+ - name: Run task 'InTestsCore'
+ shell: cmd
+ run: |
+ call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
+ ./build.cmd InTestsCore -e
+ - name: Upload test results
+ uses: actions/upload-artifact@v2
+ if: always()
+ with:
+ name: build-windows-core-trx
+ path: "**/*.trx"
+
+ build-windows-full:
runs-on: windows-latest
steps:
- - uses: actions/checkout@v3
- - name: Run
- shell: cmd
- run: |
- call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
- ./build.bat
+ - name: Disable Windows Defender
+ run: Set-MpPreference -DisableRealtimeMonitoring $true
+ shell: powershell
+ - uses: actions/checkout@v3
+ - name: Run task 'Build'
+ shell: cmd
+ run: |
+ call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
+ ./build.cmd Build
+ - name: Run task 'InTestsFull'
+ shell: cmd
+ run: |
+ call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
+ ./build.cmd InTestsFull -e
+ - name: Upload test results
+ uses: actions/upload-artifact@v2
+ if: always()
+ with:
+ name: build-windows-full-trx
+ path: "**/*.trx"
+
build-linux:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- - name: Set up Clang
- uses: egor-tensin/setup-clang@v1
- with:
- version: latest
- platform: x64
- - name: Set up zlib-static
- run: sudo apt-get install -y libkrb5-dev
- - name: Run
- run: ./build.sh
+ - uses: actions/checkout@v3
+ - name: Set up Clang
+ uses: egor-tensin/setup-clang@v1
+ with:
+ version: latest
+ platform: x64
+ - name: Set up zlib-static
+ run: sudo apt-get install -y libkrb5-dev
+ - name: Run task 'Build'
+ run: ./build.cmd Build
+ - name: Run task 'UnitTests'
+ run: ./build.cmd UnitTests -e
+ - name: Run task 'InTestsCore'
+ run: ./build.cmd InTestsCore -e
+ - name: Upload test results
+ uses: actions/upload-artifact@v2
+ if: always()
+ with:
+ name: build-linux-trx
+ path: "**/*.trx"
+
build-macos:
- runs-on: macOS-latest
+ runs-on: macos-13
+ steps:
+ - uses: actions/checkout@v3
+ - name: Run task 'Build'
+ run: ./build.cmd Build
+ - name: Run task 'UnitTests'
+ run: ./build.cmd UnitTests -e
+ - name: Run task 'InTestsCore'
+ run: ./build.cmd InTestsCore -e
+ - name: Upload test results
+ uses: actions/upload-artifact@v2
+ if: always()
+ with:
+ name: build-macos-trx
+ path: "**/*.trx"
+
+ report:
+ concurrency: ci-${{ github.ref }}
+ needs: [build-windows-full, build-windows-core, build-linux, build-macos]
+ runs-on: ubuntu-latest
+ if: always()
steps:
- - uses: actions/checkout@v3
- - name: Run
- run: ./build.sh
\ No newline at end of file
+ - uses: actions/checkout@v3
+ - name: Download Artifacts
+ uses: actions/download-artifact@v3
+ - name: Display structure of downloaded files
+ run: ls -R
+ - name: Report tests results
+ uses: dorny/test-reporter@v1
+ if: always()
+ with:
+ name: test-results
+ path: "**/*.trx"
+ reporter: dotnet-trx
+ fail-on-error: true
diff --git a/.github/workflows/docs-changelog-generate.yaml b/.github/workflows/docs-changelog-generate.yaml
index f55816e706..9afad1f814 100644
--- a/.github/workflows/docs-changelog-generate.yaml
+++ b/.github/workflows/docs-changelog-generate.yaml
@@ -19,7 +19,7 @@ jobs:
ref: master
- name: Download changelog
- run: ./build.sh --target DocFX_Changelog_Download --VersionCount 1
+ run: ./build.cmd DocsUpdate /p:Depth=1
env:
GITHUB_PRODUCT: ChangelogBuilder
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/docs-stable.yaml b/.github/workflows/docs-stable.yaml
index 83e50d7e97..089f6ed7b4 100644
--- a/.github/workflows/docs-stable.yaml
+++ b/.github/workflows/docs-stable.yaml
@@ -19,16 +19,16 @@ jobs:
ref: docs-stable
- name: Build BenchmarkDotNet
- run: ./build.bat --target Build
+ run: ./build.cmd Build
- name: Download changelog
- run: ./build.bat --target DocFX_Changelog_Download --VersionCount 1
+ run: ./build.cmd DocsUpdate /p:Depth=1
env:
GITHUB_PRODUCT: ChangelogBuilder
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build documentation
- run: ./build.bat --target DocFX_Build
+ run: ./build.cmd DocsBuild
- name: Upload Artifacts
uses: actions/upload-artifact@v1
diff --git a/.github/workflows/publish-nightly.yaml b/.github/workflows/publish-nightly.yaml
new file mode 100644
index 0000000000..8cdf355f61
--- /dev/null
+++ b/.github/workflows/publish-nightly.yaml
@@ -0,0 +1,24 @@
+name: publish-nightly
+
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ main:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set date
+ run: echo "DATE=$(date +'%Y%m%d')" >> $GITHUB_ENV
+ - name: Pack
+ run: ./build.cmd pack /p:VersionSuffix=nightly.$DATE.$GITHUB_RUN_NUMBER
+ - name: Publish nupkg
+ env:
+ MYGET_API_KEY: ${{ secrets.MYGET_API_KEY }}
+ run: .dotnet/dotnet nuget push **/*.nupkg --source https://www.myget.org/F/benchmarkdotnet/api/v3/index.json --api-key $MYGET_API_KEY --timeout 600
+ - name: Publish snupkg
+ env:
+ MYGET_API_KEY: ${{ secrets.MYGET_API_KEY }}
+ run: .dotnet/dotnet nuget push **/*.snupkg --source https://www.myget.org/F/benchmarkdotnet/api/v3/index.json --api-key $MYGET_API_KEY --timeout 600
diff --git a/appveyor.yml b/appveyor.yml
index a4c11ce797..2960c99409 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -37,7 +37,7 @@ before_build:
#---------------------------------#
build_script:
-- ps: .\build.ps1
+- ps: .\build.cmd CI
test: off
deploy: off
diff --git a/azure-pipelines.Ubuntu.yml b/azure-pipelines.Ubuntu.yml
index 4c8bf86311..a16a5446d5 100755
--- a/azure-pipelines.Ubuntu.yml
+++ b/azure-pipelines.Ubuntu.yml
@@ -13,7 +13,7 @@ jobs:
parameters:
name: Ubuntu
vmImage: 'ubuntu-20.04'
- scriptFileName: ./build.sh
+ scriptFileName: ./build.cmd CI
initialization:
- bash: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
diff --git a/azure-pipelines.Windows.yml b/azure-pipelines.Windows.yml
index 809d92e62e..34e23807f0 100755
--- a/azure-pipelines.Windows.yml
+++ b/azure-pipelines.Windows.yml
@@ -13,4 +13,4 @@ jobs:
parameters:
name: Windows
vmImage: 'windows-2019'
- scriptFileName: .\build.ps1
\ No newline at end of file
+ scriptFileName: .\build.cmd CI
\ No newline at end of file
diff --git a/azure-pipelines.macOS.yml b/azure-pipelines.macOS.yml
index 6543a8eb9b..19a34556f4 100755
--- a/azure-pipelines.macOS.yml
+++ b/azure-pipelines.macOS.yml
@@ -13,4 +13,4 @@ jobs:
parameters:
name: macOS
vmImage: 'macOS-latest'
- scriptFileName: ./build.sh
+ scriptFileName: ./build.cmd CI
diff --git a/build.cmd b/build.cmd
new file mode 100755
index 0000000000..2a8c5273ba
--- /dev/null
+++ b/build.cmd
@@ -0,0 +1,5 @@
+:<<"::CMDLITERAL"
+@CALL build\build.bat %*
+@GOTO :EOF
+::CMDLITERAL
+"$(cd "$(dirname "$0")"; pwd)/build/build.sh" "$@"
\ No newline at end of file
diff --git a/build/Build.csproj b/build/BenchmarkDotNet.Build/BenchmarkDotNet.Build.csproj
similarity index 88%
rename from build/Build.csproj
rename to build/BenchmarkDotNet.Build/BenchmarkDotNet.Build.csproj
index 6c3dc8db6a..3b5596f3b5 100644
--- a/build/Build.csproj
+++ b/build/BenchmarkDotNet.Build/BenchmarkDotNet.Build.csproj
@@ -3,13 +3,13 @@
Exe
net7.0
$(MSBuildProjectDirectory)
+ enable
-
\ No newline at end of file
diff --git a/build/BenchmarkDotNet.Build/BuildContext.cs b/build/BenchmarkDotNet.Build/BuildContext.cs
new file mode 100644
index 0000000000..416220424e
--- /dev/null
+++ b/build/BenchmarkDotNet.Build/BuildContext.cs
@@ -0,0 +1,228 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Text;
+using BenchmarkDotNet.Build.Helpers;
+using BenchmarkDotNet.Build.Meta;
+using BenchmarkDotNet.Build.Runners;
+using Cake.Common;
+using Cake.Common.Build;
+using Cake.Common.Build.AppVeyor;
+using Cake.Common.Diagnostics;
+using Cake.Common.IO;
+using Cake.Common.Tools.DotNet;
+using Cake.Common.Tools.DotNet.MSBuild;
+using Cake.Core;
+using Cake.Core.IO;
+using Cake.FileHelpers;
+using Cake.Frosting;
+using Cake.Git;
+
+namespace BenchmarkDotNet.Build;
+
+public class BuildContext : FrostingContext
+{
+ public string BuildConfiguration { get; set; } = "Release";
+ public DotNetVerbosity BuildVerbosity { get; set; } = DotNetVerbosity.Minimal;
+ public int Depth { get; set; }
+
+ public DirectoryPath RootDirectory { get; }
+ public DirectoryPath ArtifactsDirectory { get; }
+ public DirectoryPath DocsDirectory { get; }
+ public FilePath DocfxJsonFile { get; }
+
+ public DirectoryPath ChangeLogDirectory { get; }
+ public DirectoryPath ChangeLogGenDirectory { get; }
+
+ public DirectoryPath RedirectRootDirectory { get; }
+ public DirectoryPath RedirectTargetDirectory { get; }
+
+ public FilePath SolutionFile { get; }
+ public FilePath TemplatesTestsProjectFile { get; }
+ public FilePathCollection AllPackableSrcProjects { get; }
+
+ public DotNetMSBuildSettings MsBuildSettingsRestore { get; }
+ public DotNetMSBuildSettings MsBuildSettingsBuild { get; }
+ public DotNetMSBuildSettings MsBuildSettingsPack { get; }
+
+ private IAppVeyorProvider AppVeyor => this.BuildSystem().AppVeyor;
+ public bool IsRunningOnAppVeyor => AppVeyor.IsRunningOnAppVeyor;
+ public bool IsOnAppVeyorAndNotPr => IsRunningOnAppVeyor && !AppVeyor.Environment.PullRequest.IsPullRequest;
+
+ public bool IsOnAppVeyorAndBdnNightlyCiCd => IsOnAppVeyorAndNotPr &&
+ AppVeyor.Environment.Repository.Branch == "master" &&
+ this.IsRunningOnWindows();
+
+ public bool IsLocalBuild => this.BuildSystem().IsLocalBuild;
+ public bool IsCiBuild => !this.BuildSystem().IsLocalBuild;
+
+ public UnitTestRunner UnitTestRunner { get; }
+ public DocumentationRunner DocumentationRunner { get; }
+ public BuildRunner BuildRunner { get; }
+
+ public BuildContext(ICakeContext context)
+ : base(context)
+ {
+ RootDirectory = new DirectoryPath(new DirectoryInfo(Directory.GetCurrentDirectory()).Parent?.Parent?.FullName);
+ ArtifactsDirectory = RootDirectory.Combine("artifacts");
+ DocsDirectory = RootDirectory.Combine("docs");
+ DocfxJsonFile = DocsDirectory.CombineWithFilePath("docfx.json");
+
+ ChangeLogDirectory = RootDirectory.Combine("docs").Combine("changelog");
+ ChangeLogGenDirectory = RootDirectory.Combine("docs").Combine("_changelog");
+
+ RedirectRootDirectory = RootDirectory.Combine("docs").Combine("_redirects");
+ RedirectTargetDirectory = RootDirectory.Combine("docs").Combine("_site");
+
+ SolutionFile = RootDirectory.CombineWithFilePath("BenchmarkDotNet.sln");
+
+ TemplatesTestsProjectFile = RootDirectory.Combine("templates")
+ .CombineWithFilePath("BenchmarkDotNet.Templates.csproj");
+ AllPackableSrcProjects = new FilePathCollection(context.GetFiles(RootDirectory.FullPath + "/src/**/*.csproj")
+ .Where(p => !p.FullPath.Contains("Disassembler")));
+
+ MsBuildSettingsRestore = new DotNetMSBuildSettings();
+ MsBuildSettingsBuild = new DotNetMSBuildSettings();
+ MsBuildSettingsPack = new DotNetMSBuildSettings();
+
+ if (IsCiBuild)
+ {
+ System.Environment.SetEnvironmentVariable("BDN_CI_BUILD", "true");
+
+ MsBuildSettingsBuild.MaxCpuCount = 1;
+ MsBuildSettingsBuild.WithProperty("UseSharedCompilation", "false");
+ }
+
+ Depth = -1;
+ if (context.Arguments.HasArgument("msbuild"))
+ {
+ var msBuildParameters = context.Arguments.GetArguments().First(it => it.Key == "msbuild").Value;
+ foreach (var msBuildParameter in msBuildParameters)
+ {
+ var split = msBuildParameter.Split(new[] { '=' }, 2);
+ if (split.Length == 2)
+ {
+ var name = split[0];
+ var value = split[1];
+
+ MsBuildSettingsRestore.WithProperty(name, value);
+ MsBuildSettingsBuild.WithProperty(name, value);
+ MsBuildSettingsPack.WithProperty(name, value);
+
+ if (name.Equals("configuration", StringComparison.OrdinalIgnoreCase)) BuildConfiguration = value;
+
+ if (name.Equals("verbosity", StringComparison.OrdinalIgnoreCase))
+ {
+ var parsedVerbosity = Utils.ParseVerbosity(value);
+ if (parsedVerbosity != null)
+ BuildVerbosity = parsedVerbosity.Value;
+ }
+
+ if (name.Equals("depth", StringComparison.OrdinalIgnoreCase))
+ Depth = int.Parse(value);
+ }
+ }
+ }
+
+ // NativeAOT build requires VS C++ tools to be added to $path via vcvars64.bat
+ // but once we do that, dotnet restore fails with:
+ // "Please specify a valid solution configuration using the Configuration and Platform properties"
+ if (context.IsRunningOnWindows())
+ {
+ MsBuildSettingsRestore.WithProperty("Platform", "Any CPU");
+ MsBuildSettingsBuild.WithProperty("Platform", "Any CPU");
+ }
+
+ UnitTestRunner = new UnitTestRunner(this);
+ DocumentationRunner = new DocumentationRunner(this);
+ BuildRunner = new BuildRunner(this);
+ }
+
+ public void EnsureChangelogDetailsExist(bool forceClean = false)
+ {
+ var path = ChangeLogGenDirectory.Combine("details");
+ if (this.DirectoryExists(path) && forceClean)
+ this.DeleteDirectory(path, new DeleteDirectorySettings() { Force = true, Recursive = true });
+
+ if (!this.DirectoryExists(path))
+ {
+ var repo = Repo.HttpsGitUrl;
+ var branchName = Repo.ChangelogDetailsBranch;
+ var settings = new GitCloneSettings { Checkout = true, BranchName = branchName };
+ this.Information($"Trying to clone {repo} to {path} (branch: '{branchName})");
+ try
+ {
+ this.GitClone(repo, path, settings);
+ }
+ catch (Exception e)
+ {
+ this.Error($"Failed to clone {repo} to {path} (branch: '{branchName}), Exception: {e.GetType().Name}'");
+ try
+ {
+ var gitArgs = $"clone -b {branchName} {repo} {path}";
+ this.Information($"Trying to clone manually: 'git {gitArgs}'");
+ this.StartProcess("git", gitArgs);
+ }
+ catch (Exception e2)
+ {
+ throw new Exception($"Failed to clone {repo} to {path} (branch: '{branchName})'", e2);
+ }
+ }
+
+ this.Information("Clone is successfully finished");
+ this.Information("");
+ }
+ }
+
+ public void DocfxChangelogDownload(string version, string versionPrevious, string lastCommit = "")
+ {
+ EnsureChangelogDetailsExist();
+ this.Information("DocfxChangelogDownload: " + version);
+ var path = ChangeLogGenDirectory.Combine("details");
+ ChangeLogBuilder.Run(path, version, versionPrevious, lastCommit).Wait();
+ }
+
+ public void DocfxChangelogGenerate(string version)
+ {
+ EnsureChangelogDetailsExist();
+ this.Information("DocfxChangelogGenerate: " + version);
+ var header = ChangeLogGenDirectory.Combine("header").CombineWithFilePath(version + ".md");
+ var footer = ChangeLogGenDirectory.Combine("footer").CombineWithFilePath(version + ".md");
+ var details = ChangeLogGenDirectory.Combine("details").CombineWithFilePath(version + ".md");
+ var release = ChangeLogDirectory.CombineWithFilePath(version + ".md");
+
+ var content = new StringBuilder();
+ content.AppendLine("---");
+ content.AppendLine("uid: changelog." + version);
+ content.AppendLine("---");
+ content.AppendLine("");
+ content.AppendLine("# BenchmarkDotNet " + version);
+ content.AppendLine("");
+ content.AppendLine("");
+
+ if (this.FileExists(header))
+ {
+ content.AppendLine(this.FileReadText(header));
+ content.AppendLine("");
+ content.AppendLine("");
+ }
+
+ if (this.FileExists(details))
+ {
+ content.AppendLine(this.FileReadText(details));
+ content.AppendLine("");
+ content.AppendLine("");
+ }
+
+ if (this.FileExists(footer))
+ {
+ content.AppendLine("## Additional details");
+ content.AppendLine("");
+ content.AppendLine(this.FileReadText(footer));
+ }
+
+ this.FileWriteText(release, content.ToString());
+ }
+
+
+}
\ No newline at end of file
diff --git a/build/ChangeLogBuilder.cs b/build/BenchmarkDotNet.Build/ChangeLogBuilder.cs
similarity index 62%
rename from build/ChangeLogBuilder.cs
rename to build/BenchmarkDotNet.Build/ChangeLogBuilder.cs
index 561ece19b7..caf20629fc 100644
--- a/build/ChangeLogBuilder.cs
+++ b/build/BenchmarkDotNet.Build/ChangeLogBuilder.cs
@@ -5,78 +5,28 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using BenchmarkDotNet.Build.Helpers;
+using BenchmarkDotNet.Build.Meta;
using Cake.Core.IO;
-using JetBrains.Annotations;
using Octokit;
-namespace Build;
+namespace BenchmarkDotNet.Build;
-public static class OctokitExtensions
+public static class ChangeLogBuilder
{
- public static string ToStr(this User user, string prefix) => user != null
- ? $" ({prefix} [@{user.Login}]({user.HtmlUrl}))"
- : "";
-
- private static string ToStr(this Author user, string prefix) => user != null
- ? $" ({prefix} {user.ToLink()})"
- : "";
-
- private static string ToStr(this Committer user, string prefix) => user != null
- ? $" ({prefix} {user.Name})"
- : "";
-
- public static string ToLink(this Author user) => $"[@{user.Login}]({user.HtmlUrl})";
-
- public static string ToLinkWithName(this Author user, string name) => $"[@{user.Login} ({name})]({user.HtmlUrl})";
-
- public static string ToCommitMessage(this Commit commit)
- {
- var message = commit.Message.Trim().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
- .FirstOrDefault() ?? "";
- return message.Length > 80 ? message.Substring(0, 77) + "..." : message;
- }
-
- public static string ToLink(this GitHubCommit commit) => $"[{commit.Sha.Substring(0, 6)}]({commit.HtmlUrl})";
-
- public static string ToByStr(this GitHubCommit commit)
- {
- if (commit.Author != null)
- return commit.Author.ToStr("by");
- return commit.Commit.Author != null ? commit.Commit.Author.ToStr("by") : "";
- }
-}
-
-public class ChangeLogBuilder
-{
- public class Config
+ private class Config
{
- [PublicAPI] public string ProductHeader => Environment.GetEnvironmentVariable("GITHUB_PRODUCT");
- [PublicAPI] public string Token => Environment.GetEnvironmentVariable("GITHUB_TOKEN");
-
- [PublicAPI] public string RepoOwner => "dotnet";
- [PublicAPI] public string RepoName => "BenchmarkDotNet";
- [PublicAPI] public string CurrentMilestone { get; }
+ public string CurrentMilestone { get; }
+ public string PreviousMilestone { get; }
+ public string LastCommit { get; }
- [PublicAPI] public string PreviousMilestone { get; }
- [PublicAPI] public string LastCommit { get; }
-
- public void Deconstruct(out string repoOwner, out string repoName, out string currentMilestone,
- out string previousMilestone, out string lastCommit)
+ public void Deconstruct(out string currentMilestone, out string previousMilestone, out string lastCommit)
{
- repoOwner = RepoOwner;
- repoName = RepoName;
currentMilestone = CurrentMilestone;
previousMilestone = PreviousMilestone;
lastCommit = LastCommit;
}
- public Config(string[] args)
- {
- CurrentMilestone = args[0];
- PreviousMilestone = args[1];
- LastCommit = args.Length <= 2 ? CurrentMilestone : args[2];
- }
-
public Config(string currentMilestone, string previousMilestone, string lastCommit)
{
CurrentMilestone = currentMilestone;
@@ -85,20 +35,11 @@ public Config(string currentMilestone, string previousMilestone, string lastComm
}
}
- public class AuthorEqualityComparer : IEqualityComparer
- {
- public static readonly IEqualityComparer Default = new AuthorEqualityComparer();
-
- public bool Equals(Author x, Author y) => x.Login == y.Login;
-
- public int GetHashCode(Author author) => author.Login.GetHashCode();
- }
-
- public class MarkdownBuilder
+ private class MarkdownBuilder
{
- private static IReadOnlyList AllMilestones = null;
+ private static IReadOnlyList? allMilestones;
private static readonly Dictionary AuthorNames = new();
-
+
private readonly Config config;
private readonly StringBuilder builder;
@@ -115,17 +56,17 @@ private MarkdownBuilder(Config config)
private async Task Build()
{
- var (repoOwner, repoName, milestone, previousMilestone, lastCommit) = config;
+ var (milestone, previousMilestone, lastCommit) = config;
if (string.IsNullOrEmpty(lastCommit))
lastCommit = milestone;
- var client = new GitHubClient(new ProductHeaderValue(config.ProductHeader));
- var tokenAuth = new Credentials(config.Token);
+ var client = new GitHubClient(new ProductHeaderValue(Repo.ProductHeader));
+ var tokenAuth = new Credentials(Repo.Token);
client.Credentials = tokenAuth;
-
+
if (milestone == "_")
{
- var allContributors = await client.Repository.GetAllContributors(repoOwner, repoName);
+ var allContributors = await client.Repository.GetAllContributors(Repo.Owner, Repo.Name);
builder.AppendLine("# All contributors");
builder.AppendLine();
foreach (var contributor in allContributors)
@@ -140,17 +81,17 @@ private async Task Build()
return builder.ToString();
}
- if (AllMilestones == null)
+ if (allMilestones == null)
{
var milestoneRequest = new MilestoneRequest
{
State = ItemStateFilter.All
};
- AllMilestones = await client.Issue.Milestone.GetAllForRepository(repoOwner, repoName, milestoneRequest);
+ allMilestones = await client.Issue.Milestone.GetAllForRepository(Repo.Owner, Repo.Name, milestoneRequest);
}
IReadOnlyList allIssues = Array.Empty();
- var targetMilestone = AllMilestones.FirstOrDefault(m => m.Title == milestone);
+ var targetMilestone = allMilestones.FirstOrDefault(m => m.Title == milestone);
if (targetMilestone != null)
{
var issueRequest = new RepositoryIssueRequest
@@ -159,7 +100,7 @@ private async Task Build()
Milestone = targetMilestone.Number.ToString()
};
- allIssues = await client.Issue.GetAllForRepository(repoOwner, repoName, issueRequest);
+ allIssues = await client.Issue.GetAllForRepository(Repo.Owner, Repo.Name, issueRequest);
}
var issues = allIssues
@@ -170,11 +111,11 @@ private async Task Build()
.Where(issue => issue.PullRequest != null)
.OrderBy(issue => issue.Number)
.ToList();
-
- var compare = await client.Repository.Commit.Compare(repoOwner, repoName, previousMilestone, lastCommit);
+
+ var compare = await client.Repository.Commit.Compare(Repo.Owner, Repo.Name, previousMilestone, lastCommit);
var commits = compare.Commits;
-
-
+
+
foreach (var contributor in commits.Select(commit => commit.Author))
if (contributor != null && !AuthorNames.ContainsKey(contributor.Login))
{
@@ -189,14 +130,14 @@ string PresentContributor(GitHubCommit commit)
return $"{AuthorNames[commit.Author.Login]} ({commit.Author.ToLink()})".Trim();
return commit.Commit.Author.Name;
}
-
+
var contributors = compare.Commits
.Select(PresentContributor)
.OrderBy(it => it)
.Distinct()
.ToImmutableList();
-
- var milestoneHtmlUlr = $"https://github.com/{repoOwner}/{repoName}/issues?q=milestone:{milestone}";
+
+ var milestoneHtmlUlr = $"https://github.com/{Repo.Owner}/{Repo.Name}/issues?q=milestone:{milestone}";
builder.AppendLine("## Milestone details");
builder.AppendLine();
@@ -218,7 +159,7 @@ string PresentContributor(GitHubCommit commit)
}
private void AppendList(string title, IReadOnlyList items, Func format,
- string conclusion = null)
+ string? conclusion = null)
{
builder.AppendLine($"## {title} ({items.Count})");
builder.AppendLine();
@@ -233,8 +174,9 @@ private void AppendList(string title, IReadOnlyList items, Func
builder.AppendLine();
}
}
-
- public static async Task Run(DirectoryPath path, string currentMilestone, string previousMilestone, string lastCommit)
+
+ public static async Task Run(DirectoryPath path, string currentMilestone, string previousMilestone,
+ string lastCommit)
{
try
{
diff --git a/build/BenchmarkDotNet.Build/CommandLineParser.cs b/build/BenchmarkDotNet.Build/CommandLineParser.cs
new file mode 100644
index 0000000000..6f8af08a8c
--- /dev/null
+++ b/build/BenchmarkDotNet.Build/CommandLineParser.cs
@@ -0,0 +1,291 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Cake.Frosting;
+
+namespace BenchmarkDotNet.Build;
+
+public class CommandLineParser
+{
+ public static readonly CommandLineParser Instance = new();
+
+ private record Option(string ShortName, string FullName, string Arg, string Description, string CakeOption);
+
+ private readonly Option[] options =
+ {
+ new("-v",
+ "--verbosity",
+ "",
+ "Specifies the amount of information to be displayed\n(Quiet, Minimal, Normal, Verbose, Diagnostic)",
+ "--verbosity"),
+ new("-e",
+ "--exclusive",
+ "",
+ "Executes the target task without any dependencies",
+ "--exclusive")
+ };
+
+ private void PrintHelp(bool skipWelcome = false)
+ {
+ const string scriptName = "build.cmd";
+ if (!skipWelcome)
+ {
+ WriteHeader("Welcome to the BenchmarkDotNet build script!");
+ WriteLine();
+ }
+
+ WriteHeader("USAGE:");
+
+ WritePrefix();
+ Write(scriptName + " ");
+ WriteTask(" ");
+ WriteOption("[OPTIONS]");
+ WriteLine();
+
+ WriteLine();
+
+ WriteHeader("EXAMPLES:");
+
+ WritePrefix();
+ Write(scriptName + " ");
+ WriteTask("restore");
+ WriteLine();
+
+ WritePrefix();
+ Write(scriptName + " ");
+ WriteTask("build ");
+ WriteOption("/p:");
+ WriteArg("Configuration");
+ WriteOption("=");
+ WriteArg("Debug");
+ WriteLine();
+
+ WritePrefix();
+ Write(scriptName + " ");
+ WriteTask("pack ");
+ WriteOption("/p:");
+ WriteArg("Version");
+ WriteOption("=");
+ WriteArg("0.1.1729-preview");
+ WriteLine();
+
+ WritePrefix();
+ Write(scriptName + " ");
+ WriteTask("unittests ");
+ WriteOption("--exclusive --verbosity ");
+ WriteArg("Diagnostic");
+ WriteLine();
+
+ WritePrefix();
+ Write(scriptName + " ");
+ WriteTask("docsupdate ");
+ WriteOption("/p:");
+ WriteArg("Depth");
+ WriteOption("=");
+ WriteArg("3");
+ WriteLine();
+
+ WriteLine();
+
+ WriteLine("OPTIONS:", ConsoleColor.DarkCyan);
+
+ var shortNameWidth = options.Max(it => it.ShortName.Length);
+ var targetWidth = options.Max(it => it.FullName.Length + it.Arg.Length);
+
+ foreach (var (shortName, fullName, arg, description, _) in options)
+ {
+ WritePrefix();
+ WriteOption(shortName.PadRight(shortNameWidth));
+ WriteOption(shortName != "" ? "," : " ");
+ WriteOption(fullName);
+ Write(" ");
+ WriteArg(arg);
+ Write(new string(' ', targetWidth - fullName.Length - arg.Length + 3));
+ var descriptionLines = description.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
+ Write(descriptionLines.FirstOrDefault() ?? "");
+ for (int i = 1; i < descriptionLines.Length; i++)
+ {
+ WriteLine();
+ WritePrefix();
+ Write(new string(' ', shortNameWidth + 2 + targetWidth + 3));
+ Write(descriptionLines[i]);
+ }
+
+ WriteLine();
+ }
+
+ WritePrefix();
+ WriteOption("/p:");
+ WriteArg("");
+ WriteOption("=");
+ WriteArg("");
+ Write(new string(' ', targetWidth + shortNameWidth - 11));
+ Write("Passes custom properties to MSBuild");
+ WriteLine();
+
+ WriteLine();
+
+ WriteHeader("TASKS:");
+ var taskWidth = GetTaskNames().Max(name => name.Length) + 3;
+ foreach (var (taskName, taskDescription) in GetTasks())
+ {
+ if (taskName.Equals("Default", StringComparison.OrdinalIgnoreCase))
+ continue;
+
+ if (taskDescription.StartsWith("OBSOLETE", StringComparison.OrdinalIgnoreCase))
+ {
+ WriteObsolete(" " + taskName.PadRight(taskWidth));
+ WriteObsolete(taskDescription);
+ }
+ else
+ {
+ WriteTask(" " + taskName.PadRight(taskWidth));
+ Write(taskDescription);
+ }
+
+ WriteLine();
+ }
+
+ return;
+
+ void WritePrefix() => Write(" ");
+ void WriteTask(string message) => Write(message, ConsoleColor.Green);
+ void WriteOption(string message) => Write(message, ConsoleColor.Blue);
+ void WriteArg(string message) => Write(message, ConsoleColor.DarkYellow);
+ void WriteObsolete(string message) => Write(message, ConsoleColor.Gray);
+
+ void WriteHeader(string message)
+ {
+ WriteLine(message, ConsoleColor.DarkCyan);
+ }
+
+ void Write(string message, ConsoleColor? color = null)
+ {
+ if (color != null)
+ Console.ForegroundColor = color.Value;
+ Console.Write(message);
+ if (color != null)
+ Console.ResetColor();
+ }
+
+ void WriteLine(string message = "", ConsoleColor? color = null)
+ {
+ Write(message, color);
+ Console.WriteLine();
+ }
+ }
+
+ private static HashSet GetTaskNames()
+ {
+ return GetTasks().Select(task => task.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
+ }
+
+ private static List<(string Name, string Description)> GetTasks()
+ {
+ return typeof(BuildContext).Assembly
+ .GetTypes()
+ .Where(type => type.IsSubclassOf(typeof(FrostingTask)) && !type.IsAbstract)
+ .Select(type => (
+ Name: type.GetCustomAttribute()?.Name ?? "",
+ Description: type.GetCustomAttribute()?.Description ?? ""
+ ))
+ .Where(task => task.Name != "")
+ .ToList();
+ }
+
+
+ public string[]? Parse(string[]? args)
+ {
+ if (args == null || args.Length == 0)
+ {
+ PrintHelp();
+ return null;
+ }
+
+ if (args.Length == 1)
+ {
+ if (IsOneOf(args[0], "help"))
+ {
+ PrintHelp();
+ return null;
+ }
+
+ if (IsOneOf(args[0], "help-cake"))
+ {
+ new CakeHost().UseContext().Run(new[] { "--help" });
+ return null;
+ }
+ }
+
+ var argsToProcess = new Queue(args);
+
+ var taskName = argsToProcess.Dequeue();
+ if (IsOneOf(taskName, "-t", "--target") && argsToProcess.Any())
+ taskName = argsToProcess.Dequeue();
+
+ var taskNames = GetTaskNames();
+ if (!taskNames.Contains(taskName))
+ {
+ PrintError($"'{taskName}' is not a task");
+ return null;
+ }
+
+ var cakeArgs = new List
+ {
+ "--target",
+ taskName
+ };
+ while (argsToProcess.Any())
+ {
+ var arg = argsToProcess.Dequeue();
+
+ var matched = false;
+ foreach (var option in options)
+ {
+ if (IsOneOf(arg, option.ShortName, option.FullName))
+ {
+ matched = true;
+ cakeArgs.Add(option.CakeOption);
+ if (option.Arg != "")
+ {
+ if (!argsToProcess.Any())
+ {
+ PrintError(option.FullName + " is not specified");
+ return null;
+ }
+
+ cakeArgs.Add(argsToProcess.Dequeue());
+ }
+ }
+ }
+
+ if (arg.StartsWith("/p:"))
+ {
+ matched = true;
+ cakeArgs.Add("--msbuild");
+ cakeArgs.Add(arg[3..]);
+ }
+
+ if (!matched)
+ {
+ PrintError("Unknown option: " + arg);
+ return null;
+ }
+ }
+
+ return cakeArgs.ToArray();
+ }
+
+ bool IsOneOf(string arg, params string[] values) =>
+ values.Any(value => value.Equals(arg, StringComparison.OrdinalIgnoreCase));
+
+ void PrintError(string text)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.Error.WriteLine("ERROR: " + text);
+ Console.WriteLine();
+ Console.ResetColor();
+ PrintHelp(true);
+ }
+}
\ No newline at end of file
diff --git a/build/BenchmarkDotNet.Build/Folder.DotSettings b/build/BenchmarkDotNet.Build/Folder.DotSettings
new file mode 100644
index 0000000000..53109cf04e
--- /dev/null
+++ b/build/BenchmarkDotNet.Build/Folder.DotSettings
@@ -0,0 +1,4 @@
+
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ True
\ No newline at end of file
diff --git a/build/BenchmarkDotNet.Build/Helpers/OctokitExtensions.cs b/build/BenchmarkDotNet.Build/Helpers/OctokitExtensions.cs
new file mode 100644
index 0000000000..f981d6a12c
--- /dev/null
+++ b/build/BenchmarkDotNet.Build/Helpers/OctokitExtensions.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Linq;
+using Octokit;
+
+namespace BenchmarkDotNet.Build.Helpers;
+
+public static class OctokitExtensions
+{
+ public static string ToStr(this User? user, string prefix) => user != null
+ ? $" ({prefix} [@{user.Login}]({user.HtmlUrl}))"
+ : "";
+
+ private static string ToStr(this Author? user, string prefix) => user != null
+ ? $" ({prefix} {user.ToLink()})"
+ : "";
+
+ private static string ToStr(this Committer? user, string prefix) => user != null
+ ? $" ({prefix} {user.Name})"
+ : "";
+
+ public static string ToLink(this Author user) => $"[@{user.Login}]({user.HtmlUrl})";
+
+ public static string ToLinkWithName(this Author user, string name) => $"[@{user.Login} ({name})]({user.HtmlUrl})";
+
+ public static string ToCommitMessage(this Commit commit)
+ {
+ var message = commit.Message.Trim().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
+ .FirstOrDefault() ?? "";
+ return message.Length > 80 ? message.Substring(0, 77) + "..." : message;
+ }
+
+ public static string ToLink(this GitHubCommit commit) => $"[{commit.Sha.Substring(0, 6)}]({commit.HtmlUrl})";
+
+ public static string ToByStr(this GitHubCommit commit)
+ {
+ if (commit.Author != null)
+ return commit.Author.ToStr("by");
+ return commit.Commit.Author != null ? commit.Commit.Author.ToStr("by") : "";
+ }
+}
\ No newline at end of file
diff --git a/build/BenchmarkDotNet.Build/Helpers/Utils.cs b/build/BenchmarkDotNet.Build/Helpers/Utils.cs
new file mode 100644
index 0000000000..017e092419
--- /dev/null
+++ b/build/BenchmarkDotNet.Build/Helpers/Utils.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using Cake.Common.Tools.DotNet;
+
+namespace BenchmarkDotNet.Build.Helpers;
+
+public static class Utils
+{
+ public static string GetOs()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ return "linux";
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ return "windows";
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ return "macos";
+ return "unknown";
+ }
+
+ public static DotNetVerbosity? ParseVerbosity(string verbosity)
+ {
+ var lookup = new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "q", DotNetVerbosity.Quiet },
+ { "quiet", DotNetVerbosity.Quiet },
+ { "m", DotNetVerbosity.Minimal },
+ { "minimal", DotNetVerbosity.Minimal },
+ { "n", DotNetVerbosity.Normal },
+ { "normal", DotNetVerbosity.Normal },
+ { "d", DotNetVerbosity.Detailed },
+ { "detailed", DotNetVerbosity.Detailed },
+ { "diag", DotNetVerbosity.Diagnostic },
+ { "diagnostic", DotNetVerbosity.Diagnostic }
+ };
+ return lookup.TryGetValue(verbosity, out var value) ? value : null;
+ }
+}
\ No newline at end of file
diff --git a/build/BenchmarkDotNet.Build/Meta/DocumentationHelper.cs b/build/BenchmarkDotNet.Build/Meta/DocumentationHelper.cs
new file mode 100644
index 0000000000..103a6e5368
--- /dev/null
+++ b/build/BenchmarkDotNet.Build/Meta/DocumentationHelper.cs
@@ -0,0 +1,62 @@
+namespace BenchmarkDotNet.Build.Meta;
+
+public static class DocumentationHelper
+{
+ public static readonly string[] BdnAllVersions =
+ {
+ "v0.7.0",
+ "v0.7.1",
+ "v0.7.2",
+ "v0.7.3",
+ "v0.7.4",
+ "v0.7.5",
+ "v0.7.6",
+ "v0.7.7",
+ "v0.7.8",
+ "v0.8.0",
+ "v0.8.1",
+ "v0.8.2",
+ "v0.9.0",
+ "v0.9.1",
+ "v0.9.2",
+ "v0.9.3",
+ "v0.9.4",
+ "v0.9.5",
+ "v0.9.6",
+ "v0.9.7",
+ "v0.9.8",
+ "v0.9.9",
+ "v0.10.0",
+ "v0.10.1",
+ "v0.10.2",
+ "v0.10.3",
+ "v0.10.4",
+ "v0.10.5",
+ "v0.10.6",
+ "v0.10.7",
+ "v0.10.8",
+ "v0.10.9",
+ "v0.10.10",
+ "v0.10.11",
+ "v0.10.12",
+ "v0.10.13",
+ "v0.10.14",
+ "v0.11.0",
+ "v0.11.1",
+ "v0.11.2",
+ "v0.11.3",
+ "v0.11.4",
+ "v0.11.5",
+ "v0.12.0",
+ "v0.12.1",
+ "v0.13.0",
+ "v0.13.1",
+ "v0.13.2",
+ "v0.13.3",
+ "v0.13.4",
+ "v0.13.5"
+ };
+
+ public const string BdnNextVersion = "v0.13.6";
+ public const string BdnFirstCommit = "6eda98ab1e83a0d185d09ff8b24c795711af8db1";
+}
\ No newline at end of file
diff --git a/build/BenchmarkDotNet.Build/Meta/Repo.cs b/build/BenchmarkDotNet.Build/Meta/Repo.cs
new file mode 100644
index 0000000000..06e6137b55
--- /dev/null
+++ b/build/BenchmarkDotNet.Build/Meta/Repo.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace BenchmarkDotNet.Build.Meta;
+
+public static class Repo
+{
+ public const string Owner = "dotnet";
+ public const string Name = "BenchmarkDotNet";
+ public const string HttpsUrlBase = $"https://github.com/{Owner}/{Name}";
+ public const string HttpsGitUrl = $"{HttpsUrlBase}.git";
+ public const string ChangelogDetailsBranch = "docs-changelog-details";
+
+ public const string ProductHeaderVar = "GITHUB_PRODUCT";
+ public const string TokenVar = "GITHUB_TOKEN";
+
+ public static string? ProductHeader => Environment.GetEnvironmentVariable(ProductHeaderVar);
+ public static string? Token => Environment.GetEnvironmentVariable(TokenVar);
+}
\ No newline at end of file
diff --git a/build/BenchmarkDotNet.Build/Program.cs b/build/BenchmarkDotNet.Build/Program.cs
new file mode 100644
index 0000000000..4f9138bf08
--- /dev/null
+++ b/build/BenchmarkDotNet.Build/Program.cs
@@ -0,0 +1,158 @@
+using Cake.Common;
+using Cake.Frosting;
+
+namespace BenchmarkDotNet.Build;
+
+public static class Program
+{
+ public static int Main(string[] args)
+ {
+ var cakeArgs = CommandLineParser.Instance.Parse(args);
+ return cakeArgs == null
+ ? 0
+ : new CakeHost().UseContext().Run(cakeArgs);
+ }
+}
+
+[TaskName("Restore")]
+[TaskDescription("Restore NuGet packages")]
+public class RestoreTask : FrostingTask
+{
+ public override void Run(BuildContext context) => context.BuildRunner.Restore();
+}
+
+[TaskName("Build")]
+[TaskDescription("Build BenchmarkDotNet.sln solution")]
+[IsDependentOn(typeof(RestoreTask))]
+public class BuildTask : FrostingTask
+{
+ public override void Run(BuildContext context) => context.BuildRunner.Build();
+}
+
+[TaskName("UnitTests")]
+[TaskDescription("Run unit tests (fast)")]
+[IsDependentOn(typeof(BuildTask))]
+public class UnitTestsTask : FrostingTask
+{
+ public override void Run(BuildContext context) => context.UnitTestRunner.RunUnitTests();
+}
+
+[TaskName("InTestsFull")]
+[TaskDescription("Run integration tests using .NET Framework 4.6.2+ (slow)")]
+[IsDependentOn(typeof(BuildTask))]
+public class InTestsFullTask : FrostingTask
+{
+ public override bool ShouldRun(BuildContext context) =>
+ context.IsRunningOnWindows() && !context.IsRunningOnAppVeyor;
+
+ public override void Run(BuildContext context) => context.UnitTestRunner.RunInTests("net462");
+}
+
+[TaskName("InTestsCore")]
+[TaskDescription("Run integration tests using .NET 7 (slow)")]
+[IsDependentOn(typeof(BuildTask))]
+public class InTestsCoreTask : FrostingTask
+{
+ public override void Run(BuildContext context) => context.UnitTestRunner.RunInTests("net7.0");
+}
+
+[TaskName("AllTests")]
+[TaskDescription("Run all unit and integration tests (slow)")]
+[IsDependentOn(typeof(UnitTestsTask))]
+[IsDependentOn(typeof(InTestsFullTask))]
+[IsDependentOn(typeof(InTestsCoreTask))]
+public class AllTestsTask : FrostingTask
+{
+}
+
+[TaskName("Pack")]
+[TaskDescription("Pack Nupkg packages")]
+[IsDependentOn(typeof(BuildTask))]
+public class PackTask : FrostingTask
+{
+ public override void Run(BuildContext context) => context.BuildRunner.Pack();
+}
+
+[TaskName("CI")]
+[TaskDescription("Perform all CI-related tasks: Restore, Build, AllTests, Pack")]
+[IsDependentOn(typeof(BuildTask))]
+[IsDependentOn(typeof(AllTestsTask))]
+[IsDependentOn(typeof(PackTask))]
+public class CiTask : FrostingTask
+{
+}
+
+[TaskName("DocsUpdate")]
+[TaskDescription("Update generated documentation files")]
+public class DocsUpdateTask : FrostingTask
+{
+ public override void Run(BuildContext context) => context.DocumentationRunner.Update();
+}
+
+[TaskName("DocsPrepare")]
+[TaskDescription("Prepare auxiliary documentation files")]
+public class DocsPrepareTask : FrostingTask
+{
+ public override void Run(BuildContext context) => context.DocumentationRunner.Prepare();
+}
+
+// In order to work around xref issues in DocFx, BenchmarkDotNet and BenchmarkDotNet.Annotations must be build
+// before running the DocFX_Build target. However, including a dependency on BuildTask here may have unwanted
+// side effects (CleanTask).
+// TODO: Define dependencies when a CI workflow scenario for using the "DocFX_Build" target exists.
+[TaskName("DocsBuild")]
+[TaskDescription("Build final documentation")]
+[IsDependentOn(typeof(DocsPrepareTask))]
+public class DocsBuildTask : FrostingTask
+{
+ public override void Run(BuildContext context) => context.DocumentationRunner.Build();
+}
+
+[TaskName("FastTests")]
+[TaskDescription("OBSOLETE: use 'UnitTests'")]
+[IsDependentOn(typeof(UnitTestsTask))]
+public class FastTestsTask : FrostingTask
+{
+}
+
+[TaskName("SlowFullFrameworkTests")]
+[TaskDescription("OBSOLETE: use 'InTestsFull'")]
+[IsDependentOn(typeof(InTestsFullTask))]
+public class SlowFullFrameworkTestsTask : FrostingTask
+{
+}
+
+[TaskName("SlowTestsNetCore")]
+[TaskDescription("OBSOLETE: use 'InTestsCore'")]
+[IsDependentOn(typeof(InTestsCoreTask))]
+public class SlowTestsNetCoreTask : FrostingTask
+{
+}
+
+[TaskName("DocFX_Changelog_Download")]
+[TaskDescription("OBSOLETE: use 'DocsUpdate'")]
+[IsDependentOn(typeof(DocsUpdateTask))]
+public class DocFxChangelogDownloadTask : FrostingTask
+{
+}
+
+[TaskName("DocFX_Changelog_Generate")]
+[TaskDescription("OBSOLETE: use 'DocsPrepare'")]
+[IsDependentOn(typeof(DocsPrepareTask))]
+public class DocfxChangelogGenerateTask : FrostingTask
+{
+}
+
+[TaskName("DocFX_Generate_Redirects")]
+[TaskDescription("OBSOLETE: use 'DocsBuild'")]
+[IsDependentOn(typeof(DocsBuildTask))]
+public class DocfxGenerateRedirectsTask : FrostingTask
+{
+}
+
+[TaskName("DocFX_Build")]
+[TaskDescription("OBSOLETE: use 'DocsBuild'")]
+[IsDependentOn(typeof(DocsBuildTask))]
+public class DocfxBuildTask : FrostingTask
+{
+}
\ No newline at end of file
diff --git a/build/BenchmarkDotNet.Build/Runners/BuildRunner.cs b/build/BenchmarkDotNet.Build/Runners/BuildRunner.cs
new file mode 100644
index 0000000000..8ef40475d0
--- /dev/null
+++ b/build/BenchmarkDotNet.Build/Runners/BuildRunner.cs
@@ -0,0 +1,66 @@
+using Cake.Common.Build;
+using Cake.Common.Diagnostics;
+using Cake.Common.IO;
+using Cake.Common.Tools.DotNet;
+using Cake.Common.Tools.DotNet.Build;
+using Cake.Common.Tools.DotNet.Pack;
+using Cake.Common.Tools.DotNet.Restore;
+using Cake.Core;
+
+namespace BenchmarkDotNet.Build.Runners;
+
+public class BuildRunner
+{
+ private readonly BuildContext context;
+
+ public BuildRunner(BuildContext context)
+ {
+ this.context = context;
+ }
+
+ public void Restore()
+ {
+ context.DotNetRestore(context.SolutionFile.FullPath,
+ new DotNetRestoreSettings
+ {
+ MSBuildSettings = context.MsBuildSettingsRestore
+ });
+ }
+
+ public void Build()
+ {
+ context.Information("BuildSystemProvider: " + context.BuildSystem().Provider);
+ context.DotNetBuild(context.SolutionFile.FullPath, new DotNetBuildSettings
+ {
+ NoRestore = true,
+ DiagnosticOutput = true,
+ MSBuildSettings = context.MsBuildSettingsBuild,
+ Configuration = context.BuildConfiguration,
+ Verbosity = context.BuildVerbosity
+ });
+ }
+
+ public void Pack()
+ {
+ context.CleanDirectory(context.ArtifactsDirectory);
+
+ var settingsSrc = new DotNetPackSettings
+ {
+ OutputDirectory = context.ArtifactsDirectory,
+ ArgumentCustomization = args => args.Append("--include-symbols").Append("-p:SymbolPackageFormat=snupkg"),
+ MSBuildSettings = context.MsBuildSettingsPack,
+ Configuration = context.BuildConfiguration
+ };
+
+ foreach (var project in context.AllPackableSrcProjects)
+ context.DotNetPack(project.FullPath, settingsSrc);
+
+ var settingsTemplate = new DotNetPackSettings
+ {
+ OutputDirectory = context.ArtifactsDirectory,
+ MSBuildSettings = context.MsBuildSettingsPack,
+ Configuration = context.BuildConfiguration
+ };
+ context.DotNetPack(context.TemplatesTestsProjectFile.FullPath, settingsTemplate);
+ }
+}
\ No newline at end of file
diff --git a/build/BenchmarkDotNet.Build/Runners/DocumentationRunner.cs b/build/BenchmarkDotNet.Build/Runners/DocumentationRunner.cs
new file mode 100644
index 0000000000..bc7e68dfa0
--- /dev/null
+++ b/build/BenchmarkDotNet.Build/Runners/DocumentationRunner.cs
@@ -0,0 +1,168 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Text;
+using BenchmarkDotNet.Build.Meta;
+using Cake.Common.Diagnostics;
+using Cake.Common.IO;
+using Cake.Core.IO;
+using Cake.FileHelpers;
+
+namespace BenchmarkDotNet.Build.Runners;
+
+public class DocumentationRunner
+{
+ private readonly BuildContext context;
+
+ public DocumentationRunner(BuildContext context)
+ {
+ this.context = context;
+ }
+
+ private void GenerateRedirects()
+ {
+ var redirectFile = context.RedirectRootDirectory.CombineWithFilePath("_redirects");
+ if (!context.FileExists(redirectFile))
+ {
+ context.Error($"Redirect file '{redirectFile}' does not exist");
+ return;
+ }
+
+ context.EnsureDirectoryExists(context.RedirectTargetDirectory);
+
+ var redirects = context.FileReadLines(redirectFile)
+ .Select(line => line.Split(' '))
+ .Select(parts => (source: parts[0], target: parts[1]))
+ .ToList();
+
+ foreach (var (source, target) in redirects)
+ {
+ var fileName = source.StartsWith("/") || source.StartsWith("\\") ? source[1..] : source;
+ var fullFileName = context.RedirectTargetDirectory.CombineWithFilePath(fileName);
+ var content =
+ $"" +
+ $"" +
+ $"" +
+ $"{target}" +
+ $"" +
+ $"" +
+ $"" +
+ $"" +
+ $"";
+ context.EnsureDirectoryExists(fullFileName.GetDirectory());
+ context.FileWriteText(fullFileName, content);
+ }
+ }
+
+ private void RunDocfx(FilePath docfxJson)
+ {
+ context.Information($"Running docfx for '{docfxJson}'");
+
+ var currentDirectory = Directory.GetCurrentDirectory();
+ Directory.SetCurrentDirectory(docfxJson.GetDirectory().FullPath);
+ Microsoft.DocAsCode.Dotnet.DotnetApiCatalog.GenerateManagedReferenceYamlFiles(docfxJson.FullPath).Wait();
+ Microsoft.DocAsCode.Docset.Build(docfxJson.FullPath).Wait();
+ Directory.SetCurrentDirectory(currentDirectory);
+ }
+
+ private void GenerateIndexMd()
+ {
+ context.Information("DocsBuild: Generate index.md");
+ var content = new StringBuilder();
+ content.AppendLine("---");
+ content.AppendLine("title: Home");
+ content.AppendLine("---");
+ content.Append(context.FileReadText(context.RootDirectory.CombineWithFilePath("README.md")));
+ context.FileWriteText(context.DocsDirectory.CombineWithFilePath("index.md"), content.ToString());
+ }
+
+ public void Update()
+ {
+ context.EnsureChangelogDetailsExist();
+
+ ReadmeUpdater.Run(context);
+
+ if (string.IsNullOrEmpty(Repo.ProductHeader))
+ throw new Exception($"Environment variable '{Repo.ProductHeaderVar}' is not specified!");
+ if (string.IsNullOrEmpty(Repo.Token))
+ throw new Exception($"Environment variable '{Repo.TokenVar}' is not specified!");
+
+ var count = context.Depth;
+ var total = DocumentationHelper.BdnAllVersions.Length;
+
+ if (count == 0)
+ {
+ context.DocfxChangelogDownload(
+ DocumentationHelper.BdnAllVersions.First(),
+ DocumentationHelper.BdnFirstCommit);
+
+ for (int i = 1; i < total; i++)
+ context.DocfxChangelogDownload(
+ DocumentationHelper.BdnAllVersions[i],
+ DocumentationHelper.BdnAllVersions[i - 1]);
+ }
+ else if (count > 0)
+ {
+ for (int i = Math.Max(total - count, 1); i < total; i++)
+ context.DocfxChangelogDownload(
+ DocumentationHelper.BdnAllVersions[i],
+ DocumentationHelper.BdnAllVersions[i - 1]);
+ }
+
+ context.DocfxChangelogDownload(
+ DocumentationHelper.BdnNextVersion,
+ DocumentationHelper.BdnAllVersions.Last(),
+ "HEAD");
+ }
+
+ public void Prepare()
+ {
+ foreach (var version in DocumentationHelper.BdnAllVersions)
+ context.DocfxChangelogGenerate(version);
+ context.DocfxChangelogGenerate(DocumentationHelper.BdnNextVersion);
+
+ context.Information("DocfxChangelogGenerate: index.md");
+ var indexContent = new StringBuilder();
+ indexContent.AppendLine("---");
+ indexContent.AppendLine("uid: changelog");
+ indexContent.AppendLine("---");
+ indexContent.AppendLine("");
+ indexContent.AppendLine("# ChangeLog");
+ indexContent.AppendLine("");
+ foreach (var version in DocumentationHelper.BdnAllVersions.Reverse())
+ indexContent.AppendLine($"* @changelog.{version}");
+ indexContent.AppendLine("* @changelog.full");
+ context.FileWriteText(context.ChangeLogDirectory.CombineWithFilePath("index.md"), indexContent.ToString());
+
+ context.Information("DocfxChangelogGenerate: full.md");
+ var fullContent = new StringBuilder();
+ fullContent.AppendLine("---");
+ fullContent.AppendLine("uid: changelog.full");
+ fullContent.AppendLine("---");
+ fullContent.AppendLine("");
+ fullContent.AppendLine("# Full ChangeLog");
+ fullContent.AppendLine("");
+ foreach (var version in DocumentationHelper.BdnAllVersions.Reverse())
+ fullContent.AppendLine($"[!include[{version}]({version}.md)]");
+ context.FileWriteText(context.ChangeLogDirectory.CombineWithFilePath("full.md"), fullContent.ToString());
+
+ context.Information("DocfxChangelogGenerate: toc.yml");
+ var tocContent = new StringBuilder();
+ foreach (var version in DocumentationHelper.BdnAllVersions.Reverse())
+ {
+ tocContent.AppendLine($"- name: {version}");
+ tocContent.AppendLine($" href: {version}.md");
+ }
+
+ tocContent.AppendLine("- name: Full ChangeLog");
+ tocContent.AppendLine(" href: full.md");
+ context.FileWriteText(context.ChangeLogDirectory.CombineWithFilePath("toc.yml"), tocContent.ToString());
+ }
+
+ public void Build()
+ {
+ GenerateIndexMd();
+ RunDocfx(context.DocfxJsonFile);
+ GenerateRedirects();
+ }
+}
\ No newline at end of file
diff --git a/build/BenchmarkDotNet.Build/Runners/ReadmeUpdater.cs b/build/BenchmarkDotNet.Build/Runners/ReadmeUpdater.cs
new file mode 100644
index 0000000000..c040beada3
--- /dev/null
+++ b/build/BenchmarkDotNet.Build/Runners/ReadmeUpdater.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Net.Http;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using BenchmarkDotNet.Build.Meta;
+using Cake.FileHelpers;
+
+namespace BenchmarkDotNet.Build.Runners;
+
+public class ReadmeUpdater
+{
+ public static void Run(BuildContext context) => new ReadmeUpdater().RunInternal(context);
+
+ private void RunInternal(BuildContext context)
+ {
+ var dependentProjectsNumber = GetDependentProjectsNumber().Result;
+ var updaters = new LineUpdater[]
+ {
+ new(
+ "The library is adopted by",
+ @"\[(\d+)\+ GitHub projects\]",
+ dependentProjectsNumber
+ ),
+ new(
+ "BenchmarkDotNet is already adopted by more than ",
+ @"\[(\d+)\+\]",
+ dependentProjectsNumber
+ ),
+ };
+
+ var file = context.RootDirectory.CombineWithFilePath("README.md");
+ var lines = context.FileReadLines(file);
+ for (var i = 0; i < lines.Length; i++)
+ {
+ foreach (var updater in updaters)
+ lines[i] = updater.Apply(lines[i]);
+ }
+
+ context.FileWriteLines(file, lines);
+ }
+
+ private static async Task GetDependentProjectsNumber()
+ {
+ using var httpClient = new HttpClient();
+ const string url = $"{Repo.HttpsUrlBase}/network/dependents";
+ var response = await httpClient.GetAsync(new Uri(url));
+ var dependentsPage = await response.Content.ReadAsStringAsync();
+ var match = new Regex(@"([0-9\,]+)[\n\r\s]+Repositories").Match(dependentsPage);
+ var number = int.Parse(match.Groups[1].Value.Replace(",", ""));
+ number = number / 100 * 100;
+ return number;
+ }
+
+ private class LineUpdater
+ {
+ public string Prefix { get; }
+ public Regex Regex { get; }
+ public int Value { get; }
+
+ public LineUpdater(string prefix, string regex, int value)
+ {
+ Prefix = prefix;
+ Regex = new Regex(regex);
+ Value = value;
+ }
+
+ public string Apply(string line)
+ {
+ if (!line.StartsWith(Prefix))
+ return line;
+
+ var match = Regex.Match(line);
+ if (!match.Success)
+ return line;
+
+ // Groups[1] refers to the first group (\d+)
+ var numberString = match.Groups[1].Value;
+ var number = int.Parse(numberString);
+ return line.Replace(number.ToString(), Value.ToString());
+ }
+ }
+}
\ No newline at end of file
diff --git a/build/BenchmarkDotNet.Build/Runners/UnitTestRunner.cs b/build/BenchmarkDotNet.Build/Runners/UnitTestRunner.cs
new file mode 100644
index 0000000000..48d5183e14
--- /dev/null
+++ b/build/BenchmarkDotNet.Build/Runners/UnitTestRunner.cs
@@ -0,0 +1,74 @@
+using BenchmarkDotNet.Build.Helpers;
+using Cake.Common;
+using Cake.Common.Diagnostics;
+using Cake.Common.Tools.DotNet;
+using Cake.Common.Tools.DotNet.Test;
+using Cake.Core.IO;
+
+namespace BenchmarkDotNet.Build.Runners;
+
+public class UnitTestRunner
+{
+ private readonly BuildContext context;
+
+ private FilePath UnitTestsProjectFile { get; }
+ private FilePath IntegrationTestsProjectFile { get; }
+ private DirectoryPath TestOutputDirectory { get; }
+
+ public UnitTestRunner(BuildContext context)
+ {
+ this.context = context;
+ UnitTestsProjectFile = context.RootDirectory
+ .Combine("tests")
+ .Combine("BenchmarkDotNet.Tests")
+ .CombineWithFilePath("BenchmarkDotNet.Tests.csproj");
+ IntegrationTestsProjectFile = context.RootDirectory
+ .Combine("tests")
+ .Combine("BenchmarkDotNet.IntegrationTests")
+ .CombineWithFilePath("BenchmarkDotNet.IntegrationTests.csproj");
+ TestOutputDirectory = context.RootDirectory
+ .Combine("TestResults");
+ }
+
+ private DotNetTestSettings GetTestSettingsParameters(FilePath logFile, string tfm)
+ {
+ var settings = new DotNetTestSettings
+ {
+ Configuration = context.BuildConfiguration,
+ Framework = tfm,
+ NoBuild = true,
+ NoRestore = true,
+ Loggers = new[] { "trx", $"trx;LogFileName={logFile.FullPath}", "console;verbosity=detailed" },
+ EnvironmentVariables =
+ {
+ ["Platform"] = "" // force the tool to not look for the .dll in platform-specific directory
+ }
+ };
+ return settings;
+ }
+
+ private void RunTests(FilePath projectFile, string alias, string tfm)
+ {
+ var os = Utils.GetOs();
+ var trxFileName = $"{os}-{alias}-{tfm}.trx";
+ var trxFile = TestOutputDirectory.CombineWithFilePath(trxFileName);
+ var settings = GetTestSettingsParameters(trxFile, tfm);
+
+ context.Information($"Run tests for {projectFile} ({tfm}), result file: '{trxFile}'");
+ context.DotNetTest(projectFile.FullPath, settings);
+ }
+
+ private void RunUnitTests(string tfm) => RunTests(UnitTestsProjectFile, "unit", tfm);
+
+ public void RunUnitTests()
+ {
+ var targetFrameworks = context.IsRunningOnWindows()
+ ? new[] { "net462", "net7.0" }
+ : new[] { "net7.0" };
+
+ foreach (var targetFramework in targetFrameworks)
+ RunUnitTests(targetFramework);
+ }
+
+ public void RunInTests(string tfm) => RunTests(IntegrationTestsProjectFile, "integration", tfm);
+}
\ No newline at end of file
diff --git a/build/Program.cs b/build/Program.cs
deleted file mode 100644
index e816a1c49e..0000000000
--- a/build/Program.cs
+++ /dev/null
@@ -1,661 +0,0 @@
-using System;
-using System.IO;
-using System.Linq;
-using System.Net.Http;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using Build;
-using Cake.Common;
-using Cake.Common.Build;
-using Cake.Common.Build.AppVeyor;
-using Cake.Common.Diagnostics;
-using Cake.Common.IO;
-using Cake.Common.Tools.DotNet;
-using Cake.Common.Tools.DotNet.Build;
-using Cake.Common.Tools.DotNet.MSBuild;
-using Cake.Common.Tools.DotNet.Pack;
-using Cake.Common.Tools.DotNet.Restore;
-using Cake.Common.Tools.DotNet.Test;
-using Cake.Core;
-using Cake.Core.IO;
-using Cake.FileHelpers;
-using Cake.Frosting;
-using Cake.Git;
-
-public static class Program
-{
- public static int Main(string[] args)
- {
- return new CakeHost()
- .UseContext()
- .Run(args);
- }
-}
-
-public class BuildContext : FrostingContext
-{
- public string BuildConfiguration { get; set; }
- public bool SkipTests { get; set; }
- public bool SkipSlowTests { get; set; }
- public string TargetVersion { get; set; }
-
- public DirectoryPath RootDirectory { get; }
- public DirectoryPath ArtifactsDirectory { get; }
- public DirectoryPath ToolsDirectory { get; }
- public DirectoryPath DocsDirectory { get; }
- public FilePath DocfxJsonFile { get; }
- public DirectoryPath TestOutputDirectory { get; }
-
- public DirectoryPath ChangeLogDirectory { get; }
- public DirectoryPath ChangeLogGenDirectory { get; }
-
- public DirectoryPath RedirectRootDirectory { get; }
- public DirectoryPath RedirectTargetDirectory { get; }
-
- public FilePath SolutionFile { get; }
- public FilePath UnitTestsProjectFile { get; }
- public FilePath IntegrationTestsProjectFile { get; }
- public FilePath TemplatesTestsProjectFile { get; }
- public FilePathCollection AllPackableSrcProjects { get; }
-
- public DotNetMSBuildSettings MsBuildSettingsRestore { get; }
- public DotNetMSBuildSettings MsBuildSettingsBuild { get; }
- public DotNetMSBuildSettings MsBuildSettingsPack { get; }
-
- private IAppVeyorProvider AppVeyor => this.BuildSystem().AppVeyor;
- public bool IsRunningOnAppVeyor => AppVeyor.IsRunningOnAppVeyor;
- public bool IsOnAppVeyorAndNotPr => IsRunningOnAppVeyor && !AppVeyor.Environment.PullRequest.IsPullRequest;
-
- public bool IsOnAppVeyorAndBdnNightlyCiCd => IsOnAppVeyorAndNotPr &&
- AppVeyor.Environment.Repository.Branch == "master" &&
- this.IsRunningOnWindows();
-
- public bool IsLocalBuild => this.BuildSystem().IsLocalBuild;
- public bool IsCiBuild => !this.BuildSystem().IsLocalBuild;
-
- public BuildContext(ICakeContext context)
- : base(context)
- {
- BuildConfiguration = context.Argument("Configuration", "Release");
- SkipTests = context.Argument("SkipTests", false);
- SkipSlowTests = context.Argument("SkipSlowTests", false);
- TargetVersion = context.Argument("Version", "");
-
- RootDirectory = new DirectoryPath(new DirectoryInfo(Directory.GetCurrentDirectory()).Parent.FullName);
- ArtifactsDirectory = RootDirectory.Combine("artifacts");
- ToolsDirectory = RootDirectory.Combine("tools");
- DocsDirectory = RootDirectory.Combine("docs");
- DocfxJsonFile = DocsDirectory.CombineWithFilePath("docfx.json");
- TestOutputDirectory = RootDirectory.Combine("TestResults");
-
- ChangeLogDirectory = RootDirectory.Combine("docs").Combine("changelog");
- ChangeLogGenDirectory = RootDirectory.Combine("docs").Combine("_changelog");
-
- RedirectRootDirectory = RootDirectory.Combine("docs").Combine("_redirects");
- RedirectTargetDirectory = RootDirectory.Combine("docs").Combine("_site");
-
- SolutionFile = RootDirectory.CombineWithFilePath("BenchmarkDotNet.sln");
- UnitTestsProjectFile = RootDirectory.Combine("tests").Combine("BenchmarkDotNet.Tests")
- .CombineWithFilePath("BenchmarkDotNet.Tests.csproj");
- IntegrationTestsProjectFile = RootDirectory.Combine("tests").Combine("BenchmarkDotNet.IntegrationTests")
- .CombineWithFilePath("BenchmarkDotNet.IntegrationTests.csproj");
- TemplatesTestsProjectFile = RootDirectory.Combine("templates")
- .CombineWithFilePath("BenchmarkDotNet.Templates.csproj");
- AllPackableSrcProjects = new FilePathCollection(context.GetFiles(RootDirectory.FullPath + "/src/**/*.csproj")
- .Where(p => !p.FullPath.Contains("Disassembler")));
-
- MsBuildSettingsRestore = new DotNetMSBuildSettings();
- MsBuildSettingsBuild = new DotNetMSBuildSettings();
- MsBuildSettingsPack = new DotNetMSBuildSettings();
-
- if (IsCiBuild)
- {
- System.Environment.SetEnvironmentVariable("BDN_CI_BUILD", "true");
-
- MsBuildSettingsBuild.MaxCpuCount = 1;
- MsBuildSettingsBuild.WithProperty("UseSharedCompilation", "false");
- }
-
- if (!string.IsNullOrEmpty(TargetVersion))
- {
- MsBuildSettingsRestore.WithProperty("Version", TargetVersion);
- MsBuildSettingsBuild.WithProperty("Version", TargetVersion);
- MsBuildSettingsPack.WithProperty("Version", TargetVersion);
- }
-
- // NativeAOT build requires VS C++ tools to be added to $path via vcvars64.bat
- // but once we do that, dotnet restore fails with:
- // "Please specify a valid solution configuration using the Configuration and Platform properties"
- if (context.IsRunningOnWindows())
- {
- MsBuildSettingsRestore.WithProperty("Platform", "Any CPU");
- MsBuildSettingsBuild.WithProperty("Platform", "Any CPU");
- }
- }
-
- private DotNetTestSettings GetTestSettingsParameters(FilePath logFile, string tfm)
- {
- var settings = new DotNetTestSettings
- {
- Configuration = BuildConfiguration,
- Framework = tfm,
- NoBuild = true,
- NoRestore = true,
- Loggers = new[] { "trx", $"trx;LogFileName={logFile.FullPath}", "console;verbosity=detailed" }
- };
- // force the tool to not look for the .dll in platform-specific directory
- settings.EnvironmentVariables["Platform"] = "";
- return settings;
- }
-
- public void RunTests(FilePath projectFile, string alias, string tfm)
- {
- var xUnitXmlFile = TestOutputDirectory.CombineWithFilePath(alias + "-" + tfm + ".trx");
- this.Information($"Run tests for {projectFile} ({tfm}), result file: '{xUnitXmlFile}'");
- var settings = GetTestSettingsParameters(xUnitXmlFile, tfm);
- this.DotNetTest(projectFile.FullPath, settings);
- }
-
- public void EnsureChangelogDetailsExist(bool forceClean = false)
- {
- var path = ChangeLogGenDirectory.Combine("details");
- if (this.DirectoryExists(path) && forceClean)
- this.DeleteDirectory(path, new DeleteDirectorySettings() { Force = true, Recursive = true });
-
- if (!this.DirectoryExists(path))
- {
- var settings = new GitCloneSettings { Checkout = true, BranchName = "docs-changelog-details" };
- this.GitClone("https://github.com/dotnet/BenchmarkDotNet.git", path, settings);
- }
- }
-
- public void DocfxChangelogDownload(string version, string versionPrevious, string lastCommit = "")
- {
- EnsureChangelogDetailsExist(true);
- this.Information("DocfxChangelogDownload: " + version);
- // Required environment variables: GITHUB_PRODUCT, GITHUB_TOKEN
- var path = ChangeLogGenDirectory.Combine("details");
- ChangeLogBuilder.Run(path, version, versionPrevious, lastCommit).Wait();
- }
-
- public void DocfxChangelogGenerate(string version)
- {
- EnsureChangelogDetailsExist();
- this.Information("DocfxChangelogGenerate: " + version);
- var header = ChangeLogGenDirectory.Combine("header").CombineWithFilePath(version + ".md");
- var footer = ChangeLogGenDirectory.Combine("footer").CombineWithFilePath(version + ".md");
- var details = ChangeLogGenDirectory.Combine("details").CombineWithFilePath(version + ".md");
- var release = ChangeLogDirectory.CombineWithFilePath(version + ".md");
-
- var content = new StringBuilder();
- content.AppendLine("---");
- content.AppendLine("uid: changelog." + version);
- content.AppendLine("---");
- content.AppendLine("");
- content.AppendLine("# BenchmarkDotNet " + version);
- content.AppendLine("");
- content.AppendLine("");
-
- if (this.FileExists(header))
- {
- content.AppendLine(this.FileReadText(header));
- content.AppendLine("");
- content.AppendLine("");
- }
-
- if (this.FileExists(details))
- {
- content.AppendLine(this.FileReadText(details));
- content.AppendLine("");
- content.AppendLine("");
- }
-
- if (this.FileExists(footer))
- {
- content.AppendLine("## Additional details");
- content.AppendLine("");
- content.AppendLine(this.FileReadText(footer));
- }
-
- this.FileWriteText(release, content.ToString());
- }
-
- public void RunDocfx(FilePath docfxJson)
- {
- this.Information($"Running docfx for '{docfxJson}'");
-
- var currentDirectory = Directory.GetCurrentDirectory();
- Directory.SetCurrentDirectory(docfxJson.GetDirectory().FullPath);
- Microsoft.DocAsCode.Dotnet.DotnetApiCatalog.GenerateManagedReferenceYamlFiles(docfxJson.FullPath).Wait();
- Microsoft.DocAsCode.Docset.Build(docfxJson.FullPath).Wait();
- Directory.SetCurrentDirectory(currentDirectory);
- }
-
- public void GenerateRedirects()
- {
- var redirectFile = RedirectRootDirectory.CombineWithFilePath("_redirects");
- if (!this.FileExists(redirectFile))
- {
- this.Error($"Redirect file '{redirectFile}' does not exist");
- return;
- }
-
- this.EnsureDirectoryExists(RedirectTargetDirectory);
-
- var redirects = this.FileReadLines(redirectFile)
- .Select(line => line.Split(' '))
- .Select(parts => (source: parts[0], target: parts[1]))
- .ToList();
-
- foreach (var (source, target) in redirects)
- {
- var fileName = source.StartsWith("/") || source.StartsWith("\\") ? source[1..] : source;
- var fullFileName = RedirectTargetDirectory.CombineWithFilePath(fileName);
- var content =
- $"" +
- $"" +
- $"" +
- $"{target}" +
- $"" +
- $"" +
- $"" +
- $"" +
- $"";
- this.EnsureDirectoryExists(fullFileName.GetDirectory());
- this.FileWriteText(fullFileName, content);
- }
- }
-}
-
-public static class DocumentationHelper
-{
- public static readonly string[] BdnAllVersions =
- {
- "v0.7.0",
- "v0.7.1",
- "v0.7.2",
- "v0.7.3",
- "v0.7.4",
- "v0.7.5",
- "v0.7.6",
- "v0.7.7",
- "v0.7.8",
- "v0.8.0",
- "v0.8.1",
- "v0.8.2",
- "v0.9.0",
- "v0.9.1",
- "v0.9.2",
- "v0.9.3",
- "v0.9.4",
- "v0.9.5",
- "v0.9.6",
- "v0.9.7",
- "v0.9.8",
- "v0.9.9",
- "v0.10.0",
- "v0.10.1",
- "v0.10.2",
- "v0.10.3",
- "v0.10.4",
- "v0.10.5",
- "v0.10.6",
- "v0.10.7",
- "v0.10.8",
- "v0.10.9",
- "v0.10.10",
- "v0.10.11",
- "v0.10.12",
- "v0.10.13",
- "v0.10.14",
- "v0.11.0",
- "v0.11.1",
- "v0.11.2",
- "v0.11.3",
- "v0.11.4",
- "v0.11.5",
- "v0.12.0",
- "v0.12.1",
- "v0.13.0",
- "v0.13.1",
- "v0.13.2",
- "v0.13.3",
- "v0.13.4",
- "v0.13.5"
- };
-
- public const string BdnNextVersion = "v0.13.6";
- public const string BdnFirstCommit = "6eda98ab1e83a0d185d09ff8b24c795711af8db1";
-}
-
-[TaskName("Clean")]
-public class CleanTask : FrostingTask
-{
- public override void Run(BuildContext context)
- {
- context.CleanDirectory(context.ArtifactsDirectory);
- }
-}
-
-[TaskName("Restore")]
-[IsDependentOn(typeof(CleanTask))]
-public class RestoreTask : FrostingTask
-{
- public override void Run(BuildContext context)
- {
- context.DotNetRestore(context.SolutionFile.FullPath,
- new DotNetRestoreSettings
- {
- MSBuildSettings = context.MsBuildSettingsRestore
- });
- }
-}
-
-[TaskName("Build")]
-[IsDependentOn(typeof(RestoreTask))]
-public class BuildTask : FrostingTask
-{
- public override void Run(BuildContext context)
- {
- context.Information("BuildSystemProvider: " + context.BuildSystem().Provider);
- context.DotNetBuild(context.SolutionFile.FullPath, new DotNetBuildSettings
- {
- Configuration = context.BuildConfiguration,
- NoRestore = true,
- DiagnosticOutput = true,
- MSBuildSettings = context.MsBuildSettingsBuild,
- Verbosity = DotNetVerbosity.Minimal
- });
- }
-}
-
-[TaskName("FastTests")]
-[IsDependentOn(typeof(BuildTask))]
-public class FastTestsTask : FrostingTask
-{
- public override bool ShouldRun(BuildContext context)
- {
- return !context.SkipTests;
- }
-
- public override void Run(BuildContext context)
- {
- var targetFrameworks = context.IsRunningOnWindows()
- ? new[] { "net462", "net7.0" }
- : new[] { "net7.0" };
-
- foreach (var targetFramework in targetFrameworks)
- context.RunTests(context.UnitTestsProjectFile, "UnitTests", targetFramework);
- }
-}
-
-[TaskName("SlowFullFrameworkTests")]
-[IsDependentOn(typeof(BuildTask))]
-public class SlowFullFrameworkTestsTask : FrostingTask
-{
- public override bool ShouldRun(BuildContext context)
- {
- return !context.SkipTests && !context.SkipSlowTests && context.IsRunningOnWindows() &&
- !context.IsRunningOnAppVeyor;
- }
-
- public override void Run(BuildContext context)
- {
- context.RunTests(context.IntegrationTestsProjectFile, "IntegrationTests", "net462");
- }
-}
-
-[TaskName("SlowTestsNetCore")]
-[IsDependentOn(typeof(BuildTask))]
-public class SlowTestsNetCoreTask : FrostingTask
-{
- public override bool ShouldRun(BuildContext context)
- {
- return !context.SkipTests && !context.SkipSlowTests;
- }
-
- public override void Run(BuildContext context)
- {
- context.RunTests(context.IntegrationTestsProjectFile, "IntegrationTests", "net7.0");
- }
-}
-
-[TaskName("AllTests")]
-[IsDependentOn(typeof(FastTestsTask))]
-[IsDependentOn(typeof(SlowFullFrameworkTestsTask))]
-[IsDependentOn(typeof(SlowTestsNetCoreTask))]
-public class AllTestsTask : FrostingTask
-{
-}
-
-[TaskName("Pack")]
-[IsDependentOn(typeof(BuildTask))]
-public class PackTask : FrostingTask
-{
- public override bool ShouldRun(BuildContext context)
- {
- return context.IsOnAppVeyorAndBdnNightlyCiCd || context.IsLocalBuild;
- }
-
- public override void Run(BuildContext context)
- {
- var settingsSrc = new DotNetPackSettings
- {
- Configuration = context.BuildConfiguration,
- OutputDirectory = context.ArtifactsDirectory.FullPath,
- ArgumentCustomization = args => args.Append("--include-symbols").Append("-p:SymbolPackageFormat=snupkg"),
- MSBuildSettings = context.MsBuildSettingsPack
- };
-
- foreach (var project in context.AllPackableSrcProjects)
- context.DotNetPack(project.FullPath, settingsSrc);
-
- var settingsTemplate = new DotNetPackSettings
- {
- Configuration = context.BuildConfiguration,
- OutputDirectory = context.ArtifactsDirectory.FullPath
- };
- context.DotNetPack(context.TemplatesTestsProjectFile.FullPath, settingsTemplate);
- }
-}
-
-[TaskName("Default")]
-[IsDependentOn(typeof(AllTestsTask))]
-[IsDependentOn(typeof(PackTask))]
-public class DefaultTask : FrostingTask
-{
-}
-
-
-[TaskName("DocFX_Changelog_Download")]
-public class DocFxChangelogDownloadTask : FrostingTask
-{
- public override void Run(BuildContext context)
- {
- var count = context.Argument("VersionCount", -1);
- var total = DocumentationHelper.BdnAllVersions.Length;
-
- if (count == 0)
- {
- context.DocfxChangelogDownload(
- DocumentationHelper.BdnAllVersions.First(),
- DocumentationHelper.BdnFirstCommit);
-
- for (int i = 1; i < total; i++)
- context.DocfxChangelogDownload(
- DocumentationHelper.BdnAllVersions[i],
- DocumentationHelper.BdnAllVersions[i - 1]);
- }
- else if (count > 0)
- {
- for (int i = Math.Max(total - count, 1); i < total; i++)
- context.DocfxChangelogDownload(
- DocumentationHelper.BdnAllVersions[i],
- DocumentationHelper.BdnAllVersions[i - 1]);
- }
-
- context.DocfxChangelogDownload(
- DocumentationHelper.BdnNextVersion,
- DocumentationHelper.BdnAllVersions.Last(),
- "HEAD");
- }
-}
-
-[TaskName("DocFX_Changelog_Generate")]
-public class DocfxChangelogGenerateTask : FrostingTask
-{
- public override void Run(BuildContext context)
- {
- foreach (var version in DocumentationHelper.BdnAllVersions)
- context.DocfxChangelogGenerate(version);
- context.DocfxChangelogGenerate(DocumentationHelper.BdnNextVersion);
-
- context.Information("DocfxChangelogGenerate: index.md");
- var indexContent = new StringBuilder();
- indexContent.AppendLine("---");
- indexContent.AppendLine("uid: changelog");
- indexContent.AppendLine("---");
- indexContent.AppendLine("");
- indexContent.AppendLine("# ChangeLog");
- indexContent.AppendLine("");
- foreach (var version in DocumentationHelper.BdnAllVersions.Reverse())
- indexContent.AppendLine($"* @changelog.{version}");
- indexContent.AppendLine("* @changelog.full");
- context.FileWriteText(context.ChangeLogDirectory.CombineWithFilePath("index.md"), indexContent.ToString());
-
- context.Information("DocfxChangelogGenerate: full.md");
- var fullContent = new StringBuilder();
- fullContent.AppendLine("---");
- fullContent.AppendLine("uid: changelog.full");
- fullContent.AppendLine("---");
- fullContent.AppendLine("");
- fullContent.AppendLine("# Full ChangeLog");
- fullContent.AppendLine("");
- foreach (var version in DocumentationHelper.BdnAllVersions.Reverse())
- fullContent.AppendLine($"[!include[{version}]({version}.md)]");
- context.FileWriteText(context.ChangeLogDirectory.CombineWithFilePath("full.md"), fullContent.ToString());
-
- context.Information("DocfxChangelogGenerate: toc.yml");
- var tocContent = new StringBuilder();
- foreach (var version in DocumentationHelper.BdnAllVersions.Reverse())
- {
- tocContent.AppendLine($"- name: {version}");
- tocContent.AppendLine($" href: {version}.md");
- }
-
- tocContent.AppendLine("- name: Full ChangeLog");
- tocContent.AppendLine(" href: full.md");
- context.FileWriteText(context.ChangeLogDirectory.CombineWithFilePath("toc.yml"), tocContent.ToString());
- }
-}
-
-[TaskName("DocFX_Generate_Redirects")]
-public class DocfxGenerateRedirectsTask : FrostingTask
-{
- public override void Run(BuildContext context)
- {
- context.GenerateRedirects();
- }
-}
-
-// In order to work around xref issues in DocFx, BenchmarkDotNet and BenchmarkDotNet.Annotations must be build
-// before running the DocFX_Build target. However, including a dependency on BuildTask here may have unwanted
-// side effects (CleanTask).
-// TODO: Define dependencies when a CI workflow scenario for using the "DocFX_Build" target exists.
-[TaskName("DocFX_Build")]
-[IsDependentOn(typeof(DocfxChangelogGenerateTask))]
-public class DocfxBuildTask : FrostingTask
-{
- public override void Run(BuildContext context)
- {
- context.Information("DocfxBuild: Generate index.md");
- var content = new StringBuilder();
- content.AppendLine("---");
- content.AppendLine("title: Home");
- content.AppendLine("---");
- content.Append(context.FileReadText(context.RootDirectory.CombineWithFilePath("README.md")));
- context.FileWriteText(context.DocsDirectory.CombineWithFilePath("index.md"), content.ToString());
-
- context.RunDocfx(context.DocfxJsonFile);
- context.GenerateRedirects();
- }
-}
-
-[TaskName("UpdateStats")]
-public class UpdateStatsTask : FrostingTask
-{
- public class Updater
- {
- public string Prefix { get; }
- public Regex Regex { get; }
- public int Value { get; }
-
- public Updater(string prefix, string regex, int value)
- {
- Prefix = prefix;
- Regex = new Regex(regex);
- Value = value;
- }
-
- public string Apply(string line)
- {
- if (!line.StartsWith(Prefix))
- return line;
-
- var match = Regex.Match(line);
- if (!match.Success)
- return line;
-
- // Groups[1] refers to the first group (\d+)
- var numberString = match.Groups[1].Value;
- var number = int.Parse(numberString);
- return line.Replace(number.ToString(), Value.ToString());
- }
- }
-
- private static async Task GetDependentProjectsNumber()
- {
- using var httpClient = new HttpClient();
- const string url = "https://github.com/dotnet/BenchmarkDotNet/network/dependents";
- var response = await httpClient.GetAsync(new Uri(url));
- var dependentsPage = await response.Content.ReadAsStringAsync();
- var match = new Regex(@"([0-9\,]+)[\n\r\s]+Repositories").Match(dependentsPage);
- var number = int.Parse(match.Groups[1].Value.Replace(",", ""));
- number = number / 100 * 100;
- return number;
- }
-
- public override void Run(BuildContext context)
- {
- var dependentProjectsNumber = GetDependentProjectsNumber().Result;
- var updaters = new Updater[]
- {
- new(
- "The library is adopted by",
- @"\[(\d+)\+ GitHub projects\]",
- dependentProjectsNumber
- ),
- new(
- "BenchmarkDotNet is already adopted by more than ",
- @"\[(\d+)\+\]",
- dependentProjectsNumber
- ),
- };
- var files = new[]
- {
- context.RootDirectory.CombineWithFilePath("README.md")
- };
- foreach (var file in files)
- {
- var lines = context.FileReadLines(file);
- for (var i = 0; i < lines.Length; i++)
- {
- foreach (var updater in updaters)
- lines[i] = updater.Apply(lines[i]);
- }
-
- context.FileWriteLines(file, lines);
- }
- }
-}
\ No newline at end of file
diff --git a/build/azure-pipelines.job.template.yml b/build/azure-pipelines.job.template.yml
deleted file mode 100755
index d2f11f46f2..0000000000
--- a/build/azure-pipelines.job.template.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-parameters:
- name: ''
- vmImage: ''
- scriptFileName: ''
- timeoutInMinutes: 120
- initialization: []
-
-jobs:
-- job: ${{ parameters.name }}
- timeoutInMinutes: ${{ parameters.timeoutInMinutes }}
- pool:
- vmImage: ${{ parameters.vmImage }}
- steps:
- - ${{ parameters.initialization }}
- # Linux or macOS
- - bash: ${{ parameters.scriptFileName }}
- continueOnError: true
- condition: in( variables['Agent.OS'], 'Linux', 'Darwin' )
- # Windows
- - powershell: ${{ parameters.scriptFileName }}
- continueOnError: true
- condition: eq( variables['Agent.OS'], 'Windows_NT' )
- - task: PublishTestResults@2
- inputs:
- testRunner: VSTest
- testResultsFiles: '**/*.trx'
- testRunTitle: ${{ parameters.name }}
- mergeTestResults: true
- - script: 'echo 1>&2'
- failOnStderr: true
- displayName: 'If above is partially succeeded, then fail'
- condition: eq(variables['Agent.JobStatus'], 'SucceededWithIssues')
\ No newline at end of file
diff --git a/build.bat b/build/build.bat
similarity index 100%
rename from build.bat
rename to build/build.bat
diff --git a/build.ps1 b/build/build.ps1
similarity index 76%
rename from build.ps1
rename to build/build.ps1
index d33f302d65..2f6d5a5d11 100755
--- a/build.ps1
+++ b/build/build.ps1
@@ -1,16 +1,8 @@
#!/usr/bin/env pwsh
-$DotNetInstallerUri = 'https://dot.net/v1/dotnet-install.ps1';
-$DotNetUnixInstallerUri = 'https://dot.net/v1/dotnet-install.sh'
-$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
-$BuildPath = Join-Path $PSScriptRoot "build"
-
-# Make sure tools folder exists
-$ToolPath = Join-Path $PSScriptRoot "tools"
-if (!(Test-Path $ToolPath)) {
- Write-Verbose "Creating tools directory..."
- New-Item -Path $ToolPath -Type Directory -Force | out-null
-}
+$DotNetInstallerUri = 'https://dot.net/v1/dotnet-install.ps1';
+$BuildPath = Split-Path $MyInvocation.MyCommand.Path -Parent
+$PSScriptRoot = Split-Path $PSScriptRoot -Parent
if ($PSVersionTable.PSEdition -ne 'Core') {
# Attempt to set highest encryption available for SecurityProtocol.
@@ -36,7 +28,6 @@ $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
$env:DOTNET_CLI_TELEMETRY_OPTOUT=1
$env:DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX=2
-
Function Remove-PathVariable([string]$VariableToRemove)
{
$SplitChar = ';'
@@ -60,20 +51,10 @@ Function Remove-PathVariable([string]$VariableToRemove)
}
$InstallPath = Join-Path $PSScriptRoot ".dotnet"
-$GlobalJsonPath = Join-Path $BuildPath "global.json"
+$SdkPath = Join-Path $BuildPath "sdk"
+$GlobalJsonPath = Join-Path $SdkPath "global.json"
if (!(Test-Path $InstallPath)) {
New-Item -Path $InstallPath -ItemType Directory -Force | Out-Null;
-}
-
-if ($IsMacOS -or $IsLinux) {
- $ScriptPath = Join-Path $InstallPath 'dotnet-install.sh'
- (New-Object System.Net.WebClient).DownloadFile($DotNetUnixInstallerUri, $ScriptPath);
- & bash $ScriptPath --jsonfile "$GlobalJsonPath" --install-dir "$InstallPath" --no-path
-
- Remove-PathVariable "$InstallPath"
- $env:PATH = "$($InstallPath):$env:PATH"
-}
-else {
$ScriptPath = Join-Path $InstallPath 'dotnet-install.ps1'
(New-Object System.Net.WebClient).DownloadFile($DotNetInstallerUri, $ScriptPath);
& $ScriptPath -JSonFile $GlobalJsonPath -InstallDir $InstallPath;
@@ -81,11 +62,12 @@ else {
Remove-PathVariable "$InstallPath"
$env:PATH = "$InstallPath;$env:PATH"
}
+
$env:DOTNET_ROOT=$InstallPath
###########################################################################
# RUN BUILD SCRIPT
###########################################################################
-& dotnet run --project build/Build.csproj -- $args
+& dotnet run --configuration Release --project build/BenchmarkDotNet.Build/BenchmarkDotNet.Build.csproj -- $args
exit $LASTEXITCODE;
\ No newline at end of file
diff --git a/build.sh b/build/build.sh
similarity index 61%
rename from build.sh
rename to build/build.sh
index cf86d75757..ebf8ef04bd 100755
--- a/build.sh
+++ b/build/build.sh
@@ -1,13 +1,7 @@
#!/usr/bin/env bash
-# Define varibles
-SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
-TOOLS_DIR=$SCRIPT_DIR/tools
-
-# Make sure the tools folder exist.
-if [ ! -d "$TOOLS_DIR" ]; then
- mkdir "$TOOLS_DIR"
-fi
+# Define variables
+SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
###########################################################################
# INSTALL .NET CORE CLI
@@ -20,9 +14,10 @@ export DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX=2
if [ ! -d "$SCRIPT_DIR/.dotnet" ]; then
mkdir "$SCRIPT_DIR/.dotnet"
+ curl -Lsfo "$SCRIPT_DIR/.dotnet/dotnet-install.sh" https://dot.net/v1/dotnet-install.sh
+ bash "$SCRIPT_DIR/.dotnet/dotnet-install.sh" --jsonfile ./build/sdk/global.json --install-dir .dotnet --no-path
fi
-curl -Lsfo "$SCRIPT_DIR/.dotnet/dotnet-install.sh" https://dot.net/v1/dotnet-install.sh
-bash "$SCRIPT_DIR/.dotnet/dotnet-install.sh" --jsonfile ./build/global.json --install-dir .dotnet --no-path
+
export PATH="$SCRIPT_DIR/.dotnet":$PATH
export DOTNET_ROOT="$SCRIPT_DIR/.dotnet"
@@ -30,4 +25,4 @@ export DOTNET_ROOT="$SCRIPT_DIR/.dotnet"
# RUN BUILD SCRIPT
###########################################################################
-dotnet run --project ./build/Build.csproj -- "$@"
+dotnet run --configuration Release --project ./build/BenchmarkDotNet.Build/BenchmarkDotNet.Build.csproj -- "$@"
diff --git a/build/global.json b/build/sdk/global.json
similarity index 64%
rename from build/global.json
rename to build/sdk/global.json
index b44053f07a..5e4624ef91 100644
--- a/build/global.json
+++ b/build/sdk/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "7.0.304",
+ "version": "7.0.305",
"rollForward": "disable"
}
}
diff --git a/docs/articles/contributing/building.md b/docs/articles/contributing/building.md
index 71487cdaa0..b8c84ca942 100644
--- a/docs/articles/contributing/building.md
+++ b/docs/articles/contributing/building.md
@@ -6,11 +6,11 @@ There are two recommended options to build BenchmarkDotNet from source:
- [Visual Studio](https://www.visualstudio.com/downloads/) (Community, Professional, Enterprise) with .NET 4.6.2 SDK and F# support.
-- [.NET 5 SDK](https://dotnet.microsoft.com/download).
+- [.NET 7 SDK](https://dotnet.microsoft.com/download).
Once all the necessary tools are in place, building is trivial. Simply open solution file **BenchmarkDotNet.sln** that lives at the base of the repository and run Build action.
-## Cake (C# Make)
+## Command-line
[Cake (C# Make)](https://cakebuild.net/) is a cross platform build automation system with a C# DSL to do things like compiling code, copy files/folders, running unit tests, compress files and build NuGet packages.
@@ -36,19 +36,6 @@ The build currently depends on the following prerequisites:
- Install [fsharp package](https://fsharp.org/use/mac/)
- Install the latest version of [OpenSSL](https://www.openssl.org/source/).
-After you have installed these pre-requisites, you can build the BenchmarkDotNet by invoking the build script (`build.ps1` on Windows, or `build.sh` on Linux and macOS) at the base of the BenchmarkDotNet repository. By default the build process also run all the tests. There are quite a few tests, taking a significant amount of time that is not necessary if you just want to experiment with changes. You can skip the tests phase by adding the `skiptests` argument to the build script, e.g. `.\build.ps1 --SkipTests=True` or `./build.sh --skiptests=true`.
-
-Build has a number of options that you use. Some of the more important options are
-
-- **`skiptests`** - do not run the tests. This can shorten build times quite a bit. On Windows: `.\build.ps1 --SkipTests=True` or `./build.sh --skiptests=true` on Linux/macOS.
-
-- **`configuration`** - build the 'Release' or 'Debug' build type. Default value is 'Release'. On Windows: `.\build.ps1 -Configuration Debug` or `./build.sh --configuration debug` on Linux/macOS.
-
-- **`target`** - with this parameter you can run a specific target from build pipeline. Default value is 'Default' target. On Windows: `.\build.ps1 -Target Default` or `./build.sh --target default` on Linux/macOS. Available targets:
- - **`Default`** - run all actions one by one.
- - **`Clean`** - clean all `obj`, `bin` and `artifacts` directories.
- - **`Restore`** - automatically execute `Clean` action and after that restore all NuGet dependencies.
- - **`Build`** - automatically execute `Restore` action, then run MSBuild for the solution file.
- - **`FastTests`** - automatically execute `Build` action, then run all tests from the BenchmarkDotNet.Tests project.
- - **`SlowTests`** - automatically execute `Build` action, then run all tests from the BenchmarkDotNet.IntegrationTests project.
- - **`Pack`** - automatically execute `Build` action and after that creates local NuGet packages.
+In order to run various build tasks from terminal, use `build.cmd` file in the repository root.
+`build.cmd` is a cross-platform script that can be used the same way on Windows, Linux, and macOS.
+When executed without arguments, it prints help information with list of all available build tasks.
\ No newline at end of file
diff --git a/docs/articles/contributing/documentation.md b/docs/articles/contributing/documentation.md
index 6bdbc944ff..a0f23dd2d2 100644
--- a/docs/articles/contributing/documentation.md
+++ b/docs/articles/contributing/documentation.md
@@ -49,31 +49,12 @@ It will be transformed to:
## Building documentation locally
-You can build documentation locally with the help of the `DocFX_Build` Cake target.
-Use the `DocFX_Serve` Cake target to build and run the documentation.
-
-Windows (PowerShell):
-
-```
-.\build.ps1 --target DocFX_Build
-.\build.ps1 --target DocFX_Serve
-```
-
-Windows (Batch):
+You can build documentation locally with the help of the `DocsBuild` build task:
```
-.\build.bat --target DocFX_Build
-.\build.bat --target DocFX_Serve
+build.cmd DocsBuild
```
-Linux/macOS (Bash):
-
-```
-./build.sh --target DocFX_Build
-./build.sh --target DocFX_Serve
-```
-
-
## See also
* [DocFX User Manual](https://dotnet.github.io/docfx/tutorial/docfx.exe_user_manual.html)
diff --git a/docs/articles/guides/nuget.md b/docs/articles/guides/nuget.md
index 0d903802ea..0e2de62a79 100644
--- a/docs/articles/guides/nuget.md
+++ b/docs/articles/guides/nuget.md
@@ -9,17 +9,21 @@ name: Installing NuGet packages
We have the following set of NuGet packages (you can install it directly from `nuget.org`):
-* `BenchmarkDotNet`: Basic BenchmarkDotNet infrastructure and logic. This is all you need to run benchmarks.
+* `BenchmarkDotNet`: BenchmarkDotNet infrastructure and logic. This is all you need to run benchmarks.
+* `BenchmarkDotNet.Annotations`: Basic BenchmarkDotNet annotations for your benchmarks.
* `BenchmarkDotNet.Diagnostics.Windows`: an additional optional package that provides a set of Windows diagnosers.
+* `BenchmarkDotNet.Diagnostics.dotTrace`: an additional optional package that provides DotTraceDiagnoser.
* `BenchmarkDotNet.Templates`: Templates for BenchmarkDotNet.
You might find other NuGet packages that start with `BenchmarkDotNet` name, but they are internal BDN packages that should not be installed manually. All that matters are the three packages mentioned above.
## Versioning system and feeds
+
We have 3 kinds of versions: *stable*, *nightly*, and *develop*.
You can get the current version from the source code via `BenchmarkDotNetInfo.FullVersion` and the full title via `BenchmarkDotNetInfo.FullTitle`.
### Stable
+
These versions are available from the official NuGet feed.
```xml
@@ -28,26 +32,22 @@ These versions are available from the official NuGet feed.
```
-* Example of the main NuGet package: `BenchmarkDotNet.0.10.3.nupkg`.
-* Example of `BenchmarkDotNetInfo.FullTitle`: `BenchmarkDotNet v0.10.3`.
-
### Nightly
-If you want to use a nightly version of the BenchmarkDotNet, add the `https://ci.appveyor.com/nuget/benchmarkdotnet` feed in the `` section of your `NuGet.config`:
+
+If you want to use a nightly version of the BenchmarkDotNet, add the `https://www.myget.org/F/benchmarkdotnet/api/v3/index.json` feed in the `` section of your `NuGet.config`:
```xml
-
+
```
Now you can install the packages from the `bdn-nightly` feed.
-* Example of the main NuGet package: `BenchmarkDotNet.0.10.3.13.nupkg`.
-* Example of `BenchmarkDotNetInfo.FullTitle`: `BenchmarkDotNet v0.10.3.13-nightly`.
-
### Develop
-You also can build BenchmarkDotNet from source code.
-The `.nupkg` files could be build with the help of `.\build\build-and-pack.cmd`.
-* Example of the main NuGet package: `BenchmarkDotNet.0.10.3-develop.nupkg`.
-* Example of `BenchmarkDotNetInfo.FullTitle`: `BenchmarkDotNet v0.10.3.20170304-develop`.
+You also can build BenchmarkDotNet from source code:
+
+```sh
+build.cmd pack
+```
\ No newline at end of file