diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..f31f682
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,9 @@
+# A CODEOWNERS file uses a pattern that follows the same rules used in gitignore files.
+# The pattern is followed by one or more GitHub usernames or team names using the
+# standard @username or @org/team-name format. You can also refer to a user by an
+# email address that has been added to their GitHub account, for example user@example.com
+
+.github/* @reactiveui/fusillade-team
+
+* @reactiveui/fusillade-team
+version.json @reactiveui/fusillade-team
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index 6c2bdef..0000000
--- a/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,27 +0,0 @@
-***Note*: for support questions, please ask on StackOverflow: https://stackoverflow.com/questions/tagged/Fusillade . This repository's issues are reserved for feature requests and bug reports.**
-
-**Do you want to request a *feature* or report a *bug*?**
-
-
-
-**What is the current behavior?**
-
-
-
-**If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem**
-
-
-
-**What is the expected behavior?**
-
-
-
-**What is the motivation / use case for changing the behavior?**
-
-
-
-**Which versions of Fusillade, and which platform / OS are affected by this issue? Did this work in previous versions of ReativeUI? Please also test with the latest stable and snapshot (https://www.myget.org/feed/Fusillade/package/nuget/Fusillade) versions.**
-
-
-
-**Other information (e.g. stacktraces, related issues, suggestions how to fix)**
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..644f7f6
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,36 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: "[BUG] Summary of item"
+labels: Bug
+assignees: ''
+
+---
+
+Please note although we can't commit to any timeline, priority will be given to those who are [Contributors](https://github.com/reactiveui/fusillade#contribute ) to the project.
+
+If this is a question please ask on [StackOverflow](https://stackoverflow.com/questions/tagged/fusillade).
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**Steps To Reproduce**
+Provide the steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Environment(please complete the following information):**
+ - OS: [e.g. iOS]
+ - Version [e.g. 22]
+ - Device: [e.g. iPhone6]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..cc9464f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,27 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: feature request
+assignees: ''
+
+---
+
+Please note although we can't commit to any timeline, priority will be given to those who are [Contributors](https://github.com/reactiveui/fusillade#contribute ) to the project.
+
+If this is a question please ask on [StackOverflow](https://stackoverflow.com/questions/tagged/fusillade).
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is.
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Describe suggestions on how to achieve the feature**
+A clear description to how to achieve the feature.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 42bb48f..e094a75 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -10,12 +10,11 @@
-**Does this PR introduce a breaking change?**
+**What might this PR break?**
**Please check if the PR fulfills these requirements**
-- [ ] The commit follows our guidelines: https://github.com/paulcbetts/Fusillade/blob/master/CONTRIBUTING.md
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)
diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml
new file mode 100644
index 0000000..a4dce4c
--- /dev/null
+++ b/.github/release-drafter.yml
@@ -0,0 +1,4 @@
+template: |
+ ## What's Changed
+
+ $CHANGES
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 0000000..35f3968
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,17 @@
+
+
+ .NET Foundation and Contributors
+ Copyright (c) .NET Foundation and Contributors
+ MIT
+ https://github.com/reactiveui/Fusillade
+ https://github.com/reactiveui/styleguide/blob/master/logo/main.png?raw=true
+ xpaulbettsx;ghuntley;reactiveui
+ fusillade, cache, xamarin
+ https://github.com/reactiveui/Fusillade/releases
+ https://github.com/reactiveui/Fusillade
+ https://avatars0.githubusercontent.com/u/5924219?v=3&s=200
+ An HttpClient implementation for mobile apps that efficiently schedules and prioritizes requests
+ git
+ true
+
+
\ No newline at end of file
diff --git a/GitReleaseManager.yaml b/GitReleaseManager.yaml
deleted file mode 100644
index 78dd0a4..0000000
--- a/GitReleaseManager.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
-create:
- include-footer: true
- footer-heading: Where to get it
- footer-content: You can download this release from [nuget.org](https://www.nuget.org/packages/reactiveui/{milestone})
- footer-includes-milestone: true
- milestone-replace-text: '{milestone}'
-export:
- include-created-date-in-title: true
- created-date-string-format: MMMM dd, yyyy
- perform-regex-removal: true
- regex-text: '### Where to get it(\r\n)*You can .*\)'
- multiline-regex: true
-issue-labels-include:
-- Breaking change
-- Feature
-- Bug
-- Improvement
-- Documentation
-issue-labels-exclude:
-- Build
-issue-labels-alias:
- - name: Documentation
- header: Documentation
- plural: Documentation
\ No newline at end of file
diff --git a/GitVersion.yml b/GitVersion.yml
deleted file mode 100644
index f8f1587..0000000
--- a/GitVersion.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-assembly-versioning-scheme: None
-branches:
- master:
- mode: ContinuousDelivery
- tag:
- increment: Patch
- prevent-increment-of-merged-branch-version: true
- track-merge-target: false
- dev(elop)?(ment)?$:
- mode: ContinuousDeployment
- tag: alpha
- increment: Minor
- prevent-increment-of-merged-branch-version: false
- track-merge-target: true
\ No newline at end of file
diff --git a/README.md b/README.md
index 91eabda..70ef313 100644
--- a/README.md
+++ b/README.md
@@ -153,3 +153,16 @@ configure it as-needed.
### What's with the name?
The word 'Fusillade' is a synonym for Volley :)
+
+## Contribute
+
+Fusillade is developed under an OSI-approved open source license, making it freely usable and distributable, even for commercial use. Because of our Open Collective model for funding and transparency, we are able to funnel support and funds through to our contributors and community. We ❤ the people who are involved in this project, and we’d love to have you on board, especially if you are just getting started or have never contributed to open-source before.
+
+So here's to you, lovely person who wants to join us — this is how you can support us:
+
+* [Responding to questions on StackOverflow](https://stackoverflow.com/questions/tagged/fusillade)
+* [Passing on knowledge and teaching the next generation of developers](http://ericsink.com/entries/dont_use_rxui.html)
+* [Donations](https://reactiveui.net/donate) and [Corporate Sponsorships](https://reactiveui.net/sponsorship)
+* [Asking your employer to reciprocate and contribute to open-source](https://github.com/github/balanced-employee-ip-agreement)
+* Submitting documentation updates where you see fit or lacking.
+* Making contributions to the code base.
\ No newline at end of file
diff --git a/SignPackages.json b/SignPackages.json
new file mode 100644
index 0000000..3276a45
--- /dev/null
+++ b/SignPackages.json
@@ -0,0 +1,13 @@
+{
+ "SignClient": {
+ "AzureAd": {
+ "AADInstance": "https://login.microsoftonline.com/",
+ "ClientId": "c248d68a-ba6f-4aa9-8a68-71fe872063f8",
+ "TenantId": "16076fdc-fcc1-4a15-b1ca-32c9a255900e"
+ },
+ "Service": {
+ "Url": "https://codesign.dotnetfoundation.org/",
+ "ResourceId": "https://SignService/3c30251f-36f3-490b-a955-520addb85001"
+ }
+ }
+}
\ No newline at end of file
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index b4c91f3..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,48 +0,0 @@
-# configuration for "master" branch
--
- configuration: Release
- branches:
- only:
- - master
- version: 1.0.{build}
- environment:
- GITHUB_USERNAME:
- secure: 0Q9MvUId56SizmZwCf0cgg==
- GITHUB_TOKEN:
- secure: BGwPvddVVFpowTqQufqZsAemgzDseSRDQq110dJsoeP6aSXx+P5NCSi8UEfC3kSF
- NUGET_SOURCE: https://www.nuget.org/api/v2/package
- NUGET_APIKEY:
- secure: 0g2AqQxgiAIFhqoJbbmEPrJa15Z8U5xYT6vQe43Gocuxbjw74hBAIKbU+Cj65UNd
- build_script:
- - ps: >-
- ./build.cmd
- artifacts:
- - path: artifacts/*
- - path: '**/bin/*'
- test: off
-
-# configuration for "develop" branch
--
- configuration: Development
- branches:
- except:
- - master
-
- version: 1.0.{build}
- environment:
- NUGET_SOURCE: https://www.myget.org/F/fusillade/api/v2/package
- NUGET_APIKEY:
- secure: YP/3KxC2ffsuHNaolPXj66JVGzSjON9FcR2S2OEzn9c6SV14oPzUh1ySyeT+G+aA
- build_script:
- - ps: >-
- ./build.cmd
- artifacts:
- - path: artifacts/*
- - path: '**/bin/*'
- test: off
-
-# "fall back" configuration for all other branches
-# no "branches" section defined
-# do not deploy at all
--
- configuration: Development
\ No newline at end of file
diff --git a/build.cake b/build.cake
index b4848db..1666be1 100644
--- a/build.cake
+++ b/build.cake
@@ -1,21 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
//////////////////////////////////////////////////////////////////////
// ADDINS
//////////////////////////////////////////////////////////////////////
-#addin "Cake.FileHelpers"
-#addin "Cake.Coveralls"
-#addin "Cake.PinNuGetDependency"
+#addin "nuget:?package=Cake.FileHelpers&version=3.1.0"
+#addin "nuget:?package=Cake.Codecov&version=0.5.0"
+#addin "nuget:?package=Cake.Coverlet&version=2.2.1"
+#addin "nuget:?package=Cake.GitVersioning&version=2.3.38"
+
+//////////////////////////////////////////////////////////////////////
+// MODULES
+//////////////////////////////////////////////////////////////////////
+
+#module nuget:?package=Cake.DotNetTool.Module&version=0.1.0
//////////////////////////////////////////////////////////////////////
// TOOLS
//////////////////////////////////////////////////////////////////////
-#tool "GitReleaseManager"
-#tool "GitVersion.CommandLine"
-#tool "coveralls.io"
-#tool "OpenCover"
-#tool "ReportGenerator"
-#tool nuget:?package=vswhere
+#tool "nuget:?package=vswhere&version=2.5.9"
+#tool "nuget:?package=xunit.runner.console&version=2.4.1"
+#tool "nuget:?package=Codecov&version=1.1.0"
+#tool "nuget:?package=ReportGenerator&version=4.0.9"
+
+//////////////////////////////////////////////////////////////////////
+// DOTNET TOOLS
+//////////////////////////////////////////////////////////////////////
+
+#tool "dotnet:?package=SignClient&version=1.0.82"
+#tool "dotnet:?package=coverlet.console&version=1.4.1"
+#tool "dotnet:?package=nbgv&version=2.3.38"
+
+//////////////////////////////////////////////////////////////////////
+// CONSTANTS
+//////////////////////////////////////////////////////////////////////
+
+const string project = "Fusillade";
+
+// Whitelisted Packages
+var packageWhitelist = new[]
+{
+ "Fusillade",
+};
+
+var packageTestWhitelist = new[]
+{
+ "Fusillade.Tests",
+};
+
+var testFrameworks = new[] { "netcoreapp2.1" };
//////////////////////////////////////////////////////////////////////
// ARGUMENTS
@@ -27,258 +63,233 @@ if (string.IsNullOrWhiteSpace(target))
target = "Default";
}
+var configuration = Argument("configuration", "Release");
+if (string.IsNullOrWhiteSpace(configuration))
+{
+ configuration = "Release";
+}
+
//////////////////////////////////////////////////////////////////////
// PREPARATION
//////////////////////////////////////////////////////////////////////
-// Should MSBuild & GitLink treat any errors as warnings?
+// Should MSBuild treat any errors as warnings?
var treatWarningsAsErrors = false;
// Build configuration
var local = BuildSystem.IsLocalBuild;
-var isPullRequest = AppVeyor.Environment.PullRequest.IsPullRequest;
-var isRepository = StringComparer.OrdinalIgnoreCase.Equals("paulcbetts/fusillade", AppVeyor.Environment.Repository.Name);
+var isPullRequest = !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("SYSTEM_PULLREQUEST_PULLREQUESTNUMBER"));
+var isRepository = StringComparer.OrdinalIgnoreCase.Equals($"reactiveui/{project}", TFBuild.Environment.Repository.RepoName);
-var isDevelopBranch = StringComparer.OrdinalIgnoreCase.Equals("develop", AppVeyor.Environment.Repository.Branch);
-var isReleaseBranch = StringComparer.OrdinalIgnoreCase.Equals("master", AppVeyor.Environment.Repository.Branch);
-var isTagged = AppVeyor.Environment.Repository.Tag.IsTag;
-
-var githubOwner = "paulcbetts";
-var githubRepository = "fusillade";
-var githubUrl = string.Format("https://github.com/{0}/{1}", githubOwner, githubRepository);
var msBuildPath = VSWhereLatest().CombineWithFilePath("./MSBuild/15.0/Bin/MSBuild.exe");
-// Version
-var gitVersion = GitVersion();
-var majorMinorPatch = gitVersion.MajorMinorPatch;
-var informationalVersion = gitVersion.InformationalVersion;
-var nugetVersion = gitVersion.NuGetVersion;
-var buildVersion = gitVersion.FullBuildMetaData;
+var informationalVersion = EnvironmentVariable("GitAssemblyInformationalVersion");
+
+//////////////////////////////////////////////////////////////////////
+// FOLDERS
+//////////////////////////////////////////////////////////////////////
// Artifacts
var artifactDirectory = "./artifacts/";
-var packageWhitelist = new[] { "Fusillade" };
-var testCoverageOutputFile = artifactDirectory + "OpenCover.xml";
+var testsArtifactDirectory = artifactDirectory + "tests/";
+var binariesArtifactDirectory = artifactDirectory + "binaries/";
+var packagesArtifactDirectory = artifactDirectory + "packages/";
-// Macros
-Action Abort = () => { throw new Exception("a non-recoverable fatal error occurred."); };
+// OpenCover file location
+var testCoverageOutputFile = MakeAbsolute(File(testsArtifactDirectory + "TestCoverage.xml"));
///////////////////////////////////////////////////////////////////////////////
// SETUP / TEARDOWN
///////////////////////////////////////////////////////////////////////////////
-Setup((context) =>
+Setup(context =>
{
- Information("Building version {0} of Fusillade. (isTagged: {1}) Nuget Version {2}", informationalVersion, isTagged, nugetVersion);
- CreateDirectory(artifactDirectory);
+ if (!IsRunningOnWindows())
+ {
+ throw new NotImplementedException($"{project} will only build on Windows (w/Xamarin installed) because it's not possible to target UWP, WPF and Windows Forms from UNIX.");
+ }
+
+ StartProcess(Context.Tools.Resolve("nbgv*").ToString(), "cloud");
+ Information($"Building version {GitVersioningGetVersion().SemVer2} of {project}.");
+ Information($"Building on pull request {isPullRequest} of {TFBuild.Environment.Repository.RepoName}.");
+
+ CleanDirectories(artifactDirectory);
+ CreateDirectory(testsArtifactDirectory);
+ CreateDirectory(binariesArtifactDirectory);
+ CreateDirectory(packagesArtifactDirectory);
});
-Teardown((context) =>
+Teardown(context =>
{
// Executed AFTER the last task.
});
//////////////////////////////////////////////////////////////////////
-// TASKS
+// HELPER METHODS
//////////////////////////////////////////////////////////////////////
-Task("UpdateAppVeyorBuildNumber")
- .WithCriteria(() => AppVeyor.IsRunningOnAppVeyor)
- .Does(() =>
+Action Build = (solution, packageOutputPath, doNotOptimise) =>
{
- AppVeyor.UpdateBuildVersion(buildVersion);
-
-}).ReportError(exception =>
-{
- // When a build starts, the initial identifier is an auto-incremented value supplied by AppVeyor.
- // As part of the build script, this version in AppVeyor is changed to be the version obtained from
- // GitVersion. This identifier is purely cosmetic and is used by the core team to correlate a build
- // with the pull-request. In some circumstances, such as restarting a failed/cancelled build the
- // identifier in AppVeyor will be already updated and default behaviour is to throw an
- // exception/cancel the build when in fact it is safe to swallow.
- // See https://github.com/reactiveui/ReactiveUI/issues/1262
-
- Warning("Build with version {0} already exists.", buildVersion);
-});
+ Information("Building {0} using {1}", solution, msBuildPath);
+
+ var msBuildSettings = new MSBuildSettings() {
+ ToolPath = msBuildPath,
+ ArgumentCustomization = args => args.Append("/m /NoWarn:VSX1000"),
+ NodeReuse = false,
+ Restore = true
+ }
+ .WithProperty("TreatWarningsAsErrors", treatWarningsAsErrors.ToString())
+ .SetConfiguration(configuration)
+ .WithTarget("build;pack")
+ .SetVerbosity(Verbosity.Minimal);
+
+ if (!string.IsNullOrWhiteSpace(packageOutputPath))
+ {
+ msBuildSettings = msBuildSettings.WithProperty("PackageOutputPath", MakeAbsolute(Directory(packageOutputPath)).ToString().Quote());
+ }
+ if (doNotOptimise)
+ {
+ msBuildSettings = msBuildSettings.WithProperty("Optimize", "False");
+ }
-Task("Build")
- .Does (() =>
+ MSBuild(solution, msBuildSettings);
+};
+
+Action CoverageTest = (packageName) =>
{
- Action build = (solution) =>
+ var projectName = $"./src/{packageName}/{packageName}.csproj";
+ Build(projectName, null, true);
+
+ foreach (var testFramework in testFrameworks)
{
- Information("Building {0}", solution);
-
-
- MSBuild(solution, new MSBuildSettings() {
- ToolPath= msBuildPath
- }
- .WithTarget("restore;build;pack")
- .WithProperty("PackageOutputPath", MakeAbsolute(Directory(artifactDirectory)).ToString())
- .WithProperty("TreatWarningsAsErrors", treatWarningsAsErrors.ToString())
- .SetConfiguration("Release")
- // Due to https://github.com/NuGet/Home/issues/4790 and https://github.com/NuGet/Home/issues/4337 we
- // have to pass a version explicitly
- .WithProperty("Version", nugetVersion.ToString())
- .SetVerbosity(Verbosity.Minimal)
- .SetNodeReuse(false));
-
- };
-
- build("./src/Fusillade.sln");
-});
+ Information($"Performing coverage tests on {packageName}");
+
+ var testFile = $"./src/{packageName}/bin/{configuration}/{testFramework}/{packageName}.dll";
+
+ StartProcess(Context.Tools.Resolve("Coverlet*").ToString(), new ProcessSettings {
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ Arguments = new ProcessArgumentBuilder()
+ .AppendQuoted(testFile)
+ .AppendSwitch("--include", $"[{project}*]*")
+ .AppendSwitch("--exclude", "[*.Tests*]*")
+ .AppendSwitch("--exclude", "[*]*ThisAssembly*")
+ .AppendSwitch("--exclude-by-file", "*ApprovalTests*")
+ .AppendSwitchQuoted("--output", testCoverageOutputFile.ToString())
+ .AppendSwitchQuoted("--merge-with", testCoverageOutputFile.ToString())
+ .AppendSwitch("--format", "cobertura")
+ .AppendSwitch("--target", "dotnet")
+ .AppendSwitchQuoted("--targetargs", $"test {projectName} --no-build -c {configuration} --logger:trx;LogFileName=testresults-{testFramework}.trx -r {testsArtifactDirectory}")
+ });
+
+ Information($"Finished coverage testing {packageName}");
+ }
+};
-Task("RunUnitTests")
- .IsDependentOn("Build")
- .Does(() =>
-{
- // Action testAction = tool => {
-
- // tool.XUnit2("./src/Fusillade.Tests/bin/Release/**/*.Tests.dll", new XUnit2Settings {
- // OutputDirectory = artifactDirectory,
- // XmlReportV1 = true,
- // NoAppDomain = false
- // });
- // };
-
- // OpenCover(testAction,
- // testCoverageOutputFile,
- // new OpenCoverSettings {
- // ReturnTargetCodeOffset = 0,
- // ArgumentCustomization = args => args.Append("-mergeoutput")
- // }
- // .WithFilter("+[*]* -[*.Tests*]* -[Splat*]*")
- // .ExcludeByAttribute("*.ExcludeFromCodeCoverage*")
- // .ExcludeByFile("*/*Designer.cs;*/*.g.cs;*/*.g.i.cs;*splat/splat*"));
-
- // ReportGenerator(testCoverageOutputFile, artifactDirectory);
-});
+//////////////////////////////////////////////////////////////////////
+// TASKS
+//////////////////////////////////////////////////////////////////////
-Task("Package")
- .IsDependentOn("Build")
- .IsDependentOn("RunUnitTests")
- .IsDependentOn("PinNuGetDependencies")
+Task("Build")
.Does (() =>
{
-});
+ // Clean the directories since we'll need to re-generate the debug type.
+ CleanDirectories($"./src/**/obj/{configuration}");
+ CleanDirectories($"./src/**/bin/{configuration}");
-Task("PinNuGetDependencies")
- .Does (() =>
-{
- // only pin whitelisted packages.
- foreach(var package in packageWhitelist)
+ foreach(var packageName in packageWhitelist)
{
- // only pin the package which was created during this build run.
- var packagePath = artifactDirectory + File(string.Concat(package, ".", nugetVersion, ".nupkg"));
-
- // see https://github.com/cake-contrib/Cake.PinNuGetDependency
- PinNuGetDependency(packagePath, "Fusillade");
+ Build($"./src/{packageName}/{packageName}.csproj", packagesArtifactDirectory, false);
}
+
+ CopyFiles(GetFiles($"./src/**/bin/{configuration}/**/*"), Directory(binariesArtifactDirectory), true);
});
-Task("PublishPackages")
- .IsDependentOn("RunUnitTests")
- .IsDependentOn("Package")
- .WithCriteria(() => !local)
- .WithCriteria(() => !isPullRequest)
- .WithCriteria(() => isRepository)
- .WithCriteria(() => isDevelopBranch || isReleaseBranch)
- .Does (() =>
+Task("RunUnitTests")
+ .Does(() =>
{
- if (isReleaseBranch && !isTagged)
- {
- Information("Packages will not be published as this release has not been tagged.");
- return;
- }
-
- // Resolve the API key.
- var apiKey = EnvironmentVariable("NUGET_APIKEY");
- if (string.IsNullOrEmpty(apiKey))
- {
- throw new Exception("The NUGET_APIKEY environment variable is not defined.");
- }
+ // Clean the directories since we'll need to re-generate the debug type.
+ CleanDirectories($"./src/**/obj/{configuration}");
+ CleanDirectories($"./src/**/bin/{configuration}");
- var source = EnvironmentVariable("NUGET_SOURCE");
- if (string.IsNullOrEmpty(source))
+ foreach (var packageName in packageTestWhitelist)
{
- throw new Exception("The NUGET_SOURCE environment variable is not defined.");
+ CoverageTest(packageName);
}
- // only push whitelisted packages.
- foreach(var package in packageWhitelist)
- {
- // only push the package which was created during this build run.
- var packagePath = artifactDirectory + File(string.Concat(package, ".", nugetVersion, ".nupkg"));
-
- // Push the package.
- NuGetPush(packagePath, new NuGetPushSettings {
- Source = source,
- ApiKey = apiKey
- });
- }
+ ReportGenerator(testCoverageOutputFile, testsArtifactDirectory + "Report/");
+})
+.ReportError(exception =>
+{
+ var apiApprovals = GetFiles("./**/ApiApprovalTests.*");
+ CopyFiles(apiApprovals, artifactDirectory);
});
-Task("CreateRelease")
- .IsDependentOn("RunUnitTests")
- .IsDependentOn("Package")
+Task("UploadTestCoverage")
.WithCriteria(() => !local)
- .WithCriteria(() => !isPullRequest)
.WithCriteria(() => isRepository)
- .WithCriteria(() => isReleaseBranch)
- .WithCriteria(() => !isTagged)
- .Does (() =>
+ .IsDependentOn("RunUnitTests")
+ .Does(() =>
{
- var username = EnvironmentVariable("GITHUB_USERNAME");
- if (string.IsNullOrEmpty(username))
+ // Resolve the API key.
+ var token = EnvironmentVariable("CODECOV_TOKEN");
+
+ if(EnvironmentVariable("CODECOV_TOKEN") == null)
{
- throw new Exception("The GITHUB_USERNAME environment variable is not defined.");
+ throw new Exception("Codecov token not found, not sending code coverage data.");
}
- var token = EnvironmentVariable("GITHUB_TOKEN");
- if (string.IsNullOrEmpty(token))
+ if (!string.IsNullOrEmpty(token))
{
- throw new Exception("The GITHUB_TOKEN environment variable is not defined.");
- }
+ Information("Upload {0} to Codecov server", testCoverageOutputFile);
- GitReleaseManagerCreate(username, token, githubOwner, githubRepository, new GitReleaseManagerCreateSettings {
- Milestone = majorMinorPatch,
- Name = majorMinorPatch,
- Prerelease = true,
- TargetCommitish = "master"
- });
+ // Upload a coverage report.
+ Codecov(testCoverageOutputFile.ToString(), token);
+ }
});
-Task("PublishRelease")
- .IsDependentOn("RunUnitTests")
- .IsDependentOn("Package")
+Task("SignPackages")
+ .IsDependentOn("Build")
.WithCriteria(() => !local)
.WithCriteria(() => !isPullRequest)
- .WithCriteria(() => isRepository)
- .WithCriteria(() => isReleaseBranch)
- .WithCriteria(() => isTagged)
- .Does (() =>
+ .Does(() =>
{
- var username = EnvironmentVariable("GITHUB_USERNAME");
- if (string.IsNullOrEmpty(username))
+ if(EnvironmentVariable("SIGNCLIENT_SECRET") == null)
{
- throw new Exception("The GITHUB_USERNAME environment variable is not defined.");
+ throw new Exception("Client Secret not found, not signing packages.");
}
- var token = EnvironmentVariable("GITHUB_TOKEN");
- if (string.IsNullOrEmpty(token))
+ var nupkgs = GetFiles(packagesArtifactDirectory + "*.nupkg");
+ foreach(FilePath nupkg in nupkgs)
{
- throw new Exception("The GITHUB_TOKEN environment variable is not defined.");
- }
-
- // only push whitelisted packages.
- foreach(var package in packageWhitelist)
- {
- // only push the package which was created during this build run.
- var packagePath = artifactDirectory + File(string.Concat(package, ".", nugetVersion, ".nupkg"));
-
- GitReleaseManagerAddAssets(username, token, githubOwner, githubRepository, majorMinorPatch, packagePath);
+ var packageName = nupkg.GetFilenameWithoutExtension();
+ Information($"Submitting {packageName} for signing");
+
+ StartProcess(Context.Tools.Resolve("SignClient*").ToString(), new ProcessSettings {
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ Arguments = new ProcessArgumentBuilder()
+ .Append("sign")
+ .AppendSwitch("-c", "./SignPackages.json")
+ .AppendSwitch("-i", nupkg.FullPath)
+ .AppendSwitch("-r", EnvironmentVariable("SIGNCLIENT_USER"))
+ .AppendSwitch("-s", EnvironmentVariable("SIGNCLIENT_SECRET"))
+ .AppendSwitch("-n", "ReactiveUI")
+ .AppendSwitch("-d", "ReactiveUI")
+ .AppendSwitch("-u", "https://reactiveui.net")
+ });
+
+ Information($"Finished signing {packageName}");
}
+
+ Information("Sign-package complete");
+});
- GitReleaseManagerClose(username, token, githubOwner, githubRepository, majorMinorPatch);
+Task("Package")
+ .IsDependentOn("Build")
+ .IsDependentOn("SignPackages")
+ .Does (() =>
+{
});
//////////////////////////////////////////////////////////////////////
@@ -286,16 +297,13 @@ Task("PublishRelease")
//////////////////////////////////////////////////////////////////////
Task("Default")
- .IsDependentOn("UpdateAppVeyorBuildNumber")
- .IsDependentOn("CreateRelease")
- .IsDependentOn("PublishPackages")
- .IsDependentOn("PublishRelease")
+ .IsDependentOn("Package")
+ .IsDependentOn("RunUnitTests")
+ .IsDependentOn("UploadTestCoverage")
.Does (() =>
{
-
});
-
//////////////////////////////////////////////////////////////////////
// EXECUTION
//////////////////////////////////////////////////////////////////////
diff --git a/build.cmd b/build.cmd
index dae70d4..e5fa880 100644
--- a/build.cmd
+++ b/build.cmd
@@ -1,8 +1,2 @@
@echo off
-tools\nuget\nuget.exe update -self
-tools\nuget\nuget.exe install xunit.runner.console -OutputDirectory tools -ExcludeVersion
-tools\nuget\nuget.exe install Cake -OutputDirectory tools -ExcludeVersion
-
-tools\Cake\Cake.exe build.cake --target=%1
-
-exit /b %errorlevel%
+powershell -ExecutionPolicy Unrestricted ./build.ps1 %CAKE_ARGS% %*
diff --git a/build.ps1 b/build.ps1
new file mode 100644
index 0000000..27e6ef9
--- /dev/null
+++ b/build.ps1
@@ -0,0 +1,230 @@
+##########################################################################
+# This is the Cake bootstrapper script for PowerShell.
+# This file was downloaded from https://github.com/cake-build/resources
+# Feel free to change this file to fit your needs.
+##########################################################################
+
+<#
+.SYNOPSIS
+This is a Powershell script to bootstrap a Cake build.
+.DESCRIPTION
+This Powershell script will download NuGet if missing, restore NuGet tools (including Cake)
+and execute your Cake build script with the parameters you provide.
+.PARAMETER Script
+The build script to execute.
+.PARAMETER Target
+The build script target to run.
+.PARAMETER Configuration
+The build configuration to use.
+.PARAMETER Verbosity
+Specifies the amount of information to be displayed.
+.PARAMETER ShowDescription
+Shows description about tasks.
+.PARAMETER DryRun
+Performs a dry run.
+.PARAMETER Experimental
+Uses the nightly builds of the Roslyn script engine.
+.PARAMETER Mono
+Uses the Mono Compiler rather than the Roslyn script engine.
+.PARAMETER SkipToolPackageRestore
+Skips restoring of packages.
+.PARAMETER ScriptArgs
+Remaining arguments are added here.
+.LINK
+https://cakebuild.net
+#>
+
+[CmdletBinding()]
+Param(
+ [string]$Script = "build.cake",
+ [string]$Target,
+ [string]$Configuration,
+ [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
+ [string]$Verbosity,
+ [switch]$ShowDescription,
+ [Alias("WhatIf", "Noop")]
+ [switch]$DryRun,
+ [switch]$Experimental,
+ [switch]$Mono,
+ [switch]$SkipToolPackageRestore,
+ [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
+ [string[]]$ScriptArgs
+)
+
+[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
+function MD5HashFile([string] $filePath)
+{
+ if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf))
+ {
+ return $null
+ }
+
+ [System.IO.Stream] $file = $null;
+ [System.Security.Cryptography.MD5] $md5 = $null;
+ try
+ {
+ $md5 = [System.Security.Cryptography.MD5]::Create()
+ $file = [System.IO.File]::OpenRead($filePath)
+ return [System.BitConverter]::ToString($md5.ComputeHash($file))
+ }
+ finally
+ {
+ if ($file -ne $null)
+ {
+ $file.Dispose()
+ }
+ }
+}
+
+function GetProxyEnabledWebClient
+{
+ $wc = New-Object System.Net.WebClient
+ $proxy = [System.Net.WebRequest]::GetSystemWebProxy()
+ $proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials
+ $wc.Proxy = $proxy
+ return $wc
+}
+
+Write-Host "Preparing to run build script..."
+
+if(!$PSScriptRoot){
+ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
+}
+
+$TOOLS_DIR = Join-Path $PSScriptRoot "tools"
+$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins"
+$MODULES_DIR = Join-Path $TOOLS_DIR "Modules"
+$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
+$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
+$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
+$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
+$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum"
+$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config"
+$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config"
+
+# Make sure tools folder exists
+if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
+ Write-Verbose -Message "Creating tools directory..."
+ New-Item -Path $TOOLS_DIR -Type directory | out-null
+}
+
+# Make sure that packages.config exist.
+if (!(Test-Path $PACKAGES_CONFIG)) {
+ Write-Verbose -Message "Downloading packages.config..."
+ try {
+ $wc = GetProxyEnabledWebClient
+ $wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch {
+ Throw "Could not download packages.config."
+ }
+}
+
+# Try find NuGet.exe in path if not exists
+if (!(Test-Path $NUGET_EXE)) {
+ Write-Verbose -Message "Trying to find nuget.exe in PATH..."
+ $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) }
+ $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1
+ if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) {
+ Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)."
+ $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName
+ }
+}
+
+# Try download NuGet.exe if not exists
+if (!(Test-Path $NUGET_EXE)) {
+ Write-Verbose -Message "Downloading NuGet.exe..."
+ try {
+ $wc = GetProxyEnabledWebClient
+ $wc.DownloadFile($NUGET_URL, $NUGET_EXE)
+ } catch {
+ Throw "Could not download NuGet.exe."
+ }
+}
+
+# Save nuget.exe path to environment to be available to child processed
+$ENV:NUGET_EXE = $NUGET_EXE
+
+# Restore tools from NuGet?
+if(-Not $SkipToolPackageRestore.IsPresent) {
+ Push-Location
+ Set-Location $TOOLS_DIR
+
+ # Check for changes in packages.config and remove installed tools if true.
+ [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG)
+ if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or
+ ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) {
+ Write-Verbose -Message "Missing or changed package.config hash..."
+ Remove-Item * -Recurse -Exclude packages.config,nuget.exe
+ }
+
+ Write-Verbose -Message "Restoring tools from NuGet..."
+ $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
+
+ if ($LASTEXITCODE -ne 0) {
+ Throw "An error occurred while restoring NuGet tools."
+ }
+ else
+ {
+ $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
+ }
+ Write-Verbose -Message ($NuGetOutput | out-string)
+
+ Pop-Location
+}
+
+# Restore addins from NuGet
+if (Test-Path $ADDINS_PACKAGES_CONFIG) {
+ Push-Location
+ Set-Location $ADDINS_DIR
+
+ Write-Verbose -Message "Restoring addins from NuGet..."
+ $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`""
+
+ if ($LASTEXITCODE -ne 0) {
+ Throw "An error occurred while restoring NuGet addins."
+ }
+
+ Write-Verbose -Message ($NuGetOutput | out-string)
+
+ Pop-Location
+}
+
+# Restore modules from NuGet
+if (Test-Path $MODULES_PACKAGES_CONFIG) {
+ Push-Location
+ Set-Location $MODULES_DIR
+
+ Write-Verbose -Message "Restoring modules from NuGet..."
+ $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`""
+
+ if ($LASTEXITCODE -ne 0) {
+ Throw "An error occurred while restoring NuGet modules."
+ }
+
+ Write-Verbose -Message ($NuGetOutput | out-string)
+
+ Pop-Location
+}
+
+# Make sure that Cake has been installed.
+if (!(Test-Path $CAKE_EXE)) {
+ Throw "Could not find Cake.exe at $CAKE_EXE"
+}
+
+
+
+# Build Cake arguments
+$cakeArguments = @("$Script");
+if ($Target) { $cakeArguments += "-target=$Target" }
+if ($Configuration) { $cakeArguments += "-configuration=$Configuration" }
+if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" }
+if ($ShowDescription) { $cakeArguments += "-showdescription" }
+if ($DryRun) { $cakeArguments += "-dryrun" }
+if ($Experimental) { $cakeArguments += "-experimental" }
+if ($Mono) { $cakeArguments += "-mono" }
+$cakeArguments += $ScriptArgs
+
+# Start Cake
+Write-Host "Running build script..."
+&$CAKE_EXE --bootstrap
+&$CAKE_EXE $cakeArguments
+exit $LASTEXITCODE
\ No newline at end of file
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..1cda224
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,102 @@
+#!/usr/bin/env bash
+
+##########################################################################
+# This is the Cake bootstrapper script for Linux and OS X.
+# This file was downloaded from https://github.com/cake-build/resources
+# Feel free to change this file to fit your needs.
+##########################################################################
+
+# Define directories.
+SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+TOOLS_DIR=$SCRIPT_DIR/tools
+NUGET_EXE=$TOOLS_DIR/nuget.exe
+CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe
+PACKAGES_CONFIG=$TOOLS_DIR/packages.config
+PACKAGES_CONFIG_MD5=$TOOLS_DIR/packages.config.md5sum
+
+# Define md5sum or md5 depending on Linux/OSX
+MD5_EXE=
+if [[ "$(uname -s)" == "Darwin" ]]; then
+ MD5_EXE="md5 -r"
+else
+ MD5_EXE="md5sum"
+fi
+
+# Define default arguments.
+SCRIPT="build.cake"
+TARGET="Default"
+CONFIGURATION="Release"
+VERBOSITY="verbose"
+DRYRUN=
+SHOW_VERSION=false
+SCRIPT_ARGUMENTS=()
+
+# Parse arguments.
+for i in "$@"; do
+ case $1 in
+ -s|--script) SCRIPT="$2"; shift ;;
+ -t|--target) TARGET="$2"; shift ;;
+ -c|--configuration) CONFIGURATION="$2"; shift ;;
+ -v|--verbosity) VERBOSITY="$2"; shift ;;
+ -d|--dryrun) DRYRUN="-dryrun" ;;
+ --version) SHOW_VERSION=true ;;
+ --) shift; SCRIPT_ARGUMENTS+=("$@"); break ;;
+ *) SCRIPT_ARGUMENTS+=("$1") ;;
+ esac
+ shift
+done
+
+# Make sure the tools folder exist.
+if [ ! -d "$TOOLS_DIR" ]; then
+ mkdir "$TOOLS_DIR"
+fi
+
+# Make sure that packages.config exist.
+if [ ! -f "$TOOLS_DIR/packages.config" ]; then
+ echo "Downloading packages.config..."
+ curl -Lsfo "$TOOLS_DIR/packages.config" https://cakebuild.net/download/bootstrapper/packages
+ if [ $? -ne 0 ]; then
+ echo "An error occurred while downloading packages.config."
+ exit 1
+ fi
+fi
+
+# Download NuGet if it does not exist.
+if [ ! -f "$NUGET_EXE" ]; then
+ echo "Downloading NuGet..."
+ curl -Lsfo "$NUGET_EXE" https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
+ if [ $? -ne 0 ]; then
+ echo "An error occurred while downloading nuget.exe."
+ exit 1
+ fi
+fi
+
+# Restore tools from NuGet.
+pushd "$TOOLS_DIR" >/dev/null
+if [ ! -f $PACKAGES_CONFIG_MD5 ] || [ "$( cat $PACKAGES_CONFIG_MD5 | sed 's/\r$//' )" != "$( $MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' )" ]; then
+ find . -type d ! -name . | xargs rm -rf
+fi
+
+mono "$NUGET_EXE" install -ExcludeVersion
+if [ $? -ne 0 ]; then
+ echo "Could not restore NuGet packages."
+ exit 1
+fi
+
+$MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' >| $PACKAGES_CONFIG_MD5
+
+popd >/dev/null
+
+# Make sure that Cake has been installed.
+if [ ! -f "$CAKE_EXE" ]; then
+ echo "Could not find Cake.exe at '$CAKE_EXE'."
+ exit 1
+fi
+
+# Start Cake
+if $SHOW_VERSION; then
+ exec mono "$CAKE_EXE" -version
+else
+ exec mono "$CAKE_EXE" --bootstrap
+ exec mono "$CAKE_EXE" $SCRIPT -verbosity=$VERBOSITY -configuration=$CONFIGURATION -target=$TARGET $DRYRUN "${SCRIPT_ARGUMENTS[@]}"
+fi
\ No newline at end of file
diff --git a/src/ApiGeneratorGlobalSuppressions.cs b/src/ApiGeneratorGlobalSuppressions.cs
new file mode 100644
index 0000000..4cc1e89
--- /dev/null
+++ b/src/ApiGeneratorGlobalSuppressions.cs
@@ -0,0 +1,161 @@
+// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddCtorToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.MethodDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddFieldToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.FieldDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddMemberToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.IMemberDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddMethodToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.MethodDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddPropertyToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.PropertyDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateDelegateDeclaration(Mono.Cecil.TypeDefinition,System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeTypeDeclaration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateGenericArguments(Mono.Cecil.TypeReference)~System.CodeDom.CodeTypeReference[]")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateTypeDeclaration(Mono.Cecil.TypeDefinition,System.String[],System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeTypeDeclaration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetBaseTypes(Mono.Cecil.TypeDefinition)~System.Collections.Generic.IEnumerable{Mono.Cecil.TypeDefinition}")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetMethodAttributes(Mono.Cecil.MethodDefinition)~System.CodeDom.MemberAttributes")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetPropertyAttributes(System.CodeDom.MemberAttributes,System.CodeDom.MemberAttributes)~System.CodeDom.MemberAttributes")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetTypeName(Mono.Cecil.TypeReference)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.IsDotNetTypeMember(Mono.Cecil.IMemberDefinition,System.String[])~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.ModifyCodeTypeReference(System.CodeDom.CodeTypeReference,System.String)~System.CodeDom.CodeTypeReference")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.PopulateGenericParameters(Mono.Cecil.IGenericParameterProvider,System.CodeDom.CodeTypeParameterCollection)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces should not be omitted", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.PopulateMethodParameters(Mono.Cecil.IMethodSignature,System.CodeDom.CodeParameterDeclarationExpressionCollection,System.Collections.Generic.HashSet{System.String},System.Boolean)")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~F:PublicApiGenerator.ApiGenerator.defaultWhitelistedNamespacePrefixes")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~F:PublicApiGenerator.ApiGenerator.defaultWhitelistedNamespacePrefixes")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~F:PublicApiGenerator.ApiGenerator.OperatorNameMap")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~F:PublicApiGenerator.ApiGenerator.OperatorNameMap")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~F:PublicApiGenerator.ApiGenerator.SkipAttributeNames")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~F:PublicApiGenerator.ApiGenerator.SkipAttributeNames")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddCtorToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.MethodDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddCtorToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.MethodDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddFieldToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.FieldDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddFieldToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.FieldDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddMemberToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.IMemberDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddMemberToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.IMemberDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddMethodToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.MethodDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddMethodToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.MethodDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddPropertyToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.PropertyDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddPropertyToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.PropertyDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.ConvertAttributeToCode(System.Func{System.CodeDom.CodeTypeReference,System.CodeDom.CodeTypeReference},Mono.Cecil.CustomAttribute)~System.Object")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.ConvertAttributeToCode(System.Func{System.CodeDom.CodeTypeReference,System.CodeDom.CodeTypeReference},Mono.Cecil.CustomAttribute)~System.Object")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateCodeTypeReference(Mono.Cecil.TypeReference)~System.CodeDom.CodeTypeReference")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateCodeTypeReference(Mono.Cecil.TypeReference)~System.CodeDom.CodeTypeReference")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateCustomAttributes(Mono.Cecil.ICustomAttributeProvider,System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeAttributeDeclarationCollection")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateCustomAttributes(Mono.Cecil.ICustomAttributeProvider,System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeAttributeDeclarationCollection")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateDelegateDeclaration(Mono.Cecil.TypeDefinition,System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeTypeDeclaration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateDelegateDeclaration(Mono.Cecil.TypeDefinition,System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeTypeDeclaration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateGenericArguments(Mono.Cecil.TypeReference)~System.CodeDom.CodeTypeReference[]")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateGenericArguments(Mono.Cecil.TypeReference)~System.CodeDom.CodeTypeReference[]")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateInitialiserExpression(Mono.Cecil.CustomAttributeArgument)~System.CodeDom.CodeExpression")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateInitialiserExpression(Mono.Cecil.CustomAttributeArgument)~System.CodeDom.CodeExpression")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreatePublicApiForAssembly(Mono.Cecil.AssemblyDefinition,System.Func{Mono.Cecil.TypeDefinition,System.Boolean},System.Boolean,System.String[],System.Collections.Generic.HashSet{System.String})~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreatePublicApiForAssembly(Mono.Cecil.AssemblyDefinition,System.Func{Mono.Cecil.TypeDefinition,System.Boolean},System.Boolean,System.String[],System.Collections.Generic.HashSet{System.String})~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateTypeDeclaration(Mono.Cecil.TypeDefinition,System.String[],System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeTypeDeclaration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateTypeDeclaration(Mono.Cecil.TypeDefinition,System.String[],System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeTypeDeclaration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.FormatParameterConstant(Mono.Cecil.IConstantProvider)~System.Object")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.FormatParameterConstant(Mono.Cecil.IConstantProvider)~System.Object")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GenerateCodeAttributeDeclaration(System.Func{System.CodeDom.CodeTypeReference,System.CodeDom.CodeTypeReference},Mono.Cecil.CustomAttribute)~System.CodeDom.CodeAttributeDeclaration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GenerateCodeAttributeDeclaration(System.Func{System.CodeDom.CodeTypeReference,System.CodeDom.CodeTypeReference},Mono.Cecil.CustomAttribute)~System.CodeDom.CodeAttributeDeclaration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GenerateEvent(Mono.Cecil.EventDefinition,System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeTypeMember")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GenerateEvent(Mono.Cecil.EventDefinition,System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeTypeMember")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetBaseTypes(Mono.Cecil.TypeDefinition)~System.Collections.Generic.IEnumerable{Mono.Cecil.TypeDefinition}")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetBaseTypes(Mono.Cecil.TypeDefinition)~System.Collections.Generic.IEnumerable{Mono.Cecil.TypeDefinition}")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetMethodAttributes(Mono.Cecil.MethodDefinition)~System.CodeDom.MemberAttributes")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetMethodAttributes(Mono.Cecil.MethodDefinition)~System.CodeDom.MemberAttributes")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetPropertyAttributes(System.CodeDom.MemberAttributes,System.CodeDom.MemberAttributes)~System.CodeDom.MemberAttributes")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetPropertyAttributes(System.CodeDom.MemberAttributes,System.CodeDom.MemberAttributes)~System.CodeDom.MemberAttributes")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetTypeName(Mono.Cecil.TypeReference)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetTypeName(Mono.Cecil.TypeReference)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.HasVisiblePropertyMethod(System.CodeDom.MemberAttributes)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.HasVisiblePropertyMethod(System.CodeDom.MemberAttributes)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.IsCompilerGenerated(Mono.Cecil.IMemberDefinition)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.IsCompilerGenerated(Mono.Cecil.IMemberDefinition)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.IsDelegate(Mono.Cecil.TypeDefinition)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.IsDelegate(Mono.Cecil.TypeDefinition)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.IsDotNetTypeMember(Mono.Cecil.IMemberDefinition,System.String[])~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.IsDotNetTypeMember(Mono.Cecil.IMemberDefinition,System.String[])~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.IsExtensionMethod(Mono.Cecil.ICustomAttributeProvider)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.IsExtensionMethod(Mono.Cecil.ICustomAttributeProvider)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.IsHidingMethod(Mono.Cecil.MethodDefinition)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.IsHidingMethod(Mono.Cecil.MethodDefinition)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.MakeReadonly(System.CodeDom.CodeTypeReference)~System.CodeDom.CodeTypeReference")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.MakeReadonly(System.CodeDom.CodeTypeReference)~System.CodeDom.CodeTypeReference")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.ModifyCodeTypeReference(System.CodeDom.CodeTypeReference,System.String)~System.CodeDom.CodeTypeReference")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.ModifyCodeTypeReference(System.CodeDom.CodeTypeReference,System.String)~System.CodeDom.CodeTypeReference")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.NormaliseGeneratedCode(System.IO.StringWriter)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.NormaliseGeneratedCode(System.IO.StringWriter)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.NormaliseLineEndings(System.String)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.NormaliseLineEndings(System.String)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.PopulateCustomAttributes(Mono.Cecil.ICustomAttributeProvider,System.CodeDom.CodeAttributeDeclarationCollection,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.PopulateCustomAttributes(Mono.Cecil.ICustomAttributeProvider,System.CodeDom.CodeAttributeDeclarationCollection,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.PopulateCustomAttributes(Mono.Cecil.ICustomAttributeProvider,System.CodeDom.CodeAttributeDeclarationCollection,System.Func{System.CodeDom.CodeTypeReference,System.CodeDom.CodeTypeReference},System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.PopulateCustomAttributes(Mono.Cecil.ICustomAttributeProvider,System.CodeDom.CodeAttributeDeclarationCollection,System.Func{System.CodeDom.CodeTypeReference,System.CodeDom.CodeTypeReference},System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.PopulateGenericParameters(Mono.Cecil.IGenericParameterProvider,System.CodeDom.CodeTypeParameterCollection)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.PopulateGenericParameters(Mono.Cecil.IGenericParameterProvider,System.CodeDom.CodeTypeParameterCollection)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.PopulateMethodParameters(Mono.Cecil.IMethodSignature,System.CodeDom.CodeParameterDeclarationExpressionCollection,System.Collections.Generic.HashSet{System.String},System.Boolean)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.PopulateMethodParameters(Mono.Cecil.IMethodSignature,System.CodeDom.CodeParameterDeclarationExpressionCollection,System.Collections.Generic.HashSet{System.String},System.Boolean)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.RemoveUnnecessaryWhiteSpace(System.String)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.RemoveUnnecessaryWhiteSpace(System.String)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.ShouldIncludeAttribute(Mono.Cecil.CustomAttribute,System.Collections.Generic.HashSet{System.String})~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.ShouldIncludeAttribute(Mono.Cecil.CustomAttribute,System.Collections.Generic.HashSet{System.String})~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.ShouldIncludeMember(Mono.Cecil.IMemberDefinition,System.String[])~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.ShouldIncludeMember(Mono.Cecil.IMemberDefinition,System.String[])~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.ShouldIncludeType(Mono.Cecil.TypeDefinition)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.ShouldIncludeType(Mono.Cecil.TypeDefinition)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.ShouldOutputBaseType(Mono.Cecil.TypeDefinition)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.ShouldOutputBaseType(Mono.Cecil.TypeDefinition)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1400:Access modifier should be declared", Justification = "NuGet Inclusion", Scope = "type", Target = "~T:PublicApiGenerator.CecilEx")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Readability", "RCS1018:Add default access modifier.", Justification = "NuGet Inclusion", Scope = "type", Target = "~T:PublicApiGenerator.CecilEx")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1009:Closing parenthesis should be spaced correctly", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddMemberToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.IMemberDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1003:Symbols should be spaced correctly", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddMemberToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.IMemberDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1009:Closing parenthesis should be spaced correctly", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateInitialiserExpression(Mono.Cecil.CustomAttributeArgument)~System.CodeDom.CodeExpression")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1003:Symbols should be spaced correctly", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateInitialiserExpression(Mono.Cecil.CustomAttributeArgument)~System.CodeDom.CodeExpression")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1009:Closing parenthesis should be spaced correctly", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetPropertyAttributes(System.CodeDom.MemberAttributes,System.CodeDom.MemberAttributes)~System.CodeDom.MemberAttributes")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1003:Symbols should be spaced correctly", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetPropertyAttributes(System.CodeDom.MemberAttributes,System.CodeDom.MemberAttributes)~System.CodeDom.MemberAttributes")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1009:Closing parenthesis should be spaced correctly", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.RemoveUnnecessaryWhiteSpace(System.String)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1122:Use string.Empty for empty strings", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GetTypeName(Mono.Cecil.TypeReference)~System.String")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateInitialiserExpression(Mono.Cecil.CustomAttributeArgument)~System.CodeDom.CodeExpression")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1513:Closing brace should be followed by blank line", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddPropertyToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.PropertyDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1513:Closing brace should be followed by blank line", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateGenericArguments(Mono.Cecil.TypeReference)~System.CodeDom.CodeTypeReference[]")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1513:Closing brace should be followed by blank line", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreatePublicApiForAssembly(Mono.Cecil.AssemblyDefinition,System.Func{Mono.Cecil.TypeDefinition,System.Boolean},System.Boolean,System.String[],System.Collections.Generic.HashSet{System.String})~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1513:Closing brace should be followed by blank line", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateTypeDeclaration(Mono.Cecil.TypeDefinition,System.String[],System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeTypeDeclaration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1513:Closing brace should be followed by blank line", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GenerateCodeAttributeDeclaration(System.Func{System.CodeDom.CodeTypeReference,System.CodeDom.CodeTypeReference},Mono.Cecil.CustomAttribute)~System.CodeDom.CodeAttributeDeclaration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1513:Closing brace should be followed by blank line", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.PopulateGenericParameters(Mono.Cecil.IGenericParameterProvider,System.CodeDom.CodeTypeParameterCollection)")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "RCS1001:Add braces (when expression spans over multiple lines).", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateTypeDeclaration(Mono.Cecil.TypeDefinition,System.String[],System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeTypeDeclaration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1117:Parameters should be on same line or separate lines", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.GeneratePublicApi(System.Reflection.Assembly,System.Type[],System.Boolean,System.String[],System.String[])~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1117:Parameters should be on same line or separate lines", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.NormaliseGeneratedCode(System.IO.StringWriter)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1116:Split parameters should start on line after declaration", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddMemberToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.IMemberDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1116:Split parameters should start on line after declaration", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddPropertyToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.PropertyDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1116:Split parameters should start on line after declaration", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateCustomAttributes(Mono.Cecil.ICustomAttributeProvider,System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeAttributeDeclarationCollection")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1116:Split parameters should start on line after declaration", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.PopulateCustomAttributes(Mono.Cecil.ICustomAttributeProvider,System.CodeDom.CodeAttributeDeclarationCollection,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1116:Split parameters should start on line after declaration", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.PopulateCustomAttributes(Mono.Cecil.ICustomAttributeProvider,System.CodeDom.CodeAttributeDeclarationCollection,System.Func{System.CodeDom.CodeTypeReference,System.CodeDom.CodeTypeReference},System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1116:Split parameters should start on line after declaration", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.PopulateMethodParameters(Mono.Cecil.IMethodSignature,System.CodeDom.CodeParameterDeclarationExpressionCollection,System.Collections.Generic.HashSet{System.String},System.Boolean)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1116:Split parameters should start on line after declaration", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.RemoveUnnecessaryWhiteSpace(System.String)~System.String")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1000:Keywords should be spaced correctly", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateTypeDeclaration(Mono.Cecil.TypeDefinition,System.String[],System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeTypeDeclaration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1209:Using alias directives should be placed after other using directives", Justification = "NuGet Inclusion")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1210:Using directives should be ordered alphabetically by namespace", Justification = "NuGet Inclusion")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1208:System using directives should be placed before other using directives", Justification = "NuGet Inclusion")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "NuGet Inclusion", Scope = "member", Target = "~F:PublicApiGenerator.ApiGenerator.OperatorNameMap")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "NuGet Inclusion", Scope = "member", Target = "~F:PublicApiGenerator.ApiGenerator.SkipAttributeNames")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1825:Avoid zero-length array allocations.", Justification = "NuGet Inclusion", Scope = "member", Target = "~F:PublicApiGenerator.ApiGenerator.defaultWhitelistedNamespacePrefixes")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddMethodToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.MethodDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.IsDotNetTypeMember(Mono.Cecil.IMemberDefinition,System.String[])~System.Boolean")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1512:Single-line comments should not be followed by blank line", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddPropertyToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.PropertyDefinition,System.Collections.Generic.HashSet{System.String})")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1515:Single-line comment should be preceded by blank line", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.AddMethodToTypeDeclaration(System.CodeDom.CodeTypeDeclaration,Mono.Cecil.MethodDefinition,System.Collections.Generic.HashSet{System.String})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1515:Single-line comment should be preceded by blank line", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateTypeDeclaration(Mono.Cecil.TypeDefinition,System.String[],System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeTypeDeclaration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1520:Use braces consistently", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateTypeDeclaration(Mono.Cecil.TypeDefinition,System.String[],System.Collections.Generic.HashSet{System.String})~System.CodeDom.CodeTypeDeclaration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "NuGet Inclusion", Scope = "type", Target = "~T:PublicApiGenerator.CecilEx")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1005:Single line comments should begin with single space", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.CreateInitialiserExpression(Mono.Cecil.CustomAttributeArgument)~System.CodeDom.CodeExpression")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1111:Closing parenthesis should be on line of last parameter", Justification = "NuGet Inclusion", Scope = "member", Target = "~M:PublicApiGenerator.ApiGenerator.RemoveUnnecessaryWhiteSpace(System.String)~System.String")]
diff --git a/src/Directory.build.props b/src/Directory.build.props
new file mode 100644
index 0000000..bfe75bf
--- /dev/null
+++ b/src/Directory.build.props
@@ -0,0 +1,58 @@
+
+
+ Fusilllade ($(TargetFramework))
+ true
+ $(NoWarn);VSX1000
+ AnyCPU
+ $(MSBuildProjectName.Contains('Tests'))
+ embedded
+
+ true
+
+ true
+
+ $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
+ $(MSBuildThisFileDirectory)analyzers.ruleset
+
+
+ $(MSBuildThisFileDirectory)analyzers.tests.ruleset
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Fusillade.Tests/Fusillade.Tests.csproj b/src/Fusillade.Tests/Fusillade.Tests.csproj
index cc046e0..c399a44 100644
--- a/src/Fusillade.Tests/Fusillade.Tests.csproj
+++ b/src/Fusillade.Tests/Fusillade.Tests.csproj
@@ -1,84 +1,18 @@
-
-
-
+
- Debug
- AnyCPU
- {BA0745E4-4566-4655-B83C-B4398F67DC39}
- Library
- Properties
- Fusillade.Tests
- Fusillade.Tests
- v4.6.1
- 512
-
+ netcoreapp2.1
+ false
+ $(NoWarn);CS1591
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {26493c47-6a4a-4f2a-9f92-046aa8cd95cc}
- Fusillade
-
-
+
-
- 6.0.0-alpha0038
-
-
- 1.1.0-beta.69
-
-
- 8.0.0-alpha0073
-
-
- 8.0.0-alpha0073
-
-
- 3.1.1
-
-
- 2.2.0
-
+
+
-
+
+
+
+
-
\ No newline at end of file
diff --git a/src/Fusillade.Tests/Http/BaseHttpSchedulerSharedTests.cs b/src/Fusillade.Tests/Http/BaseHttpSchedulerSharedTests.cs
new file mode 100644
index 0000000..ee67902
--- /dev/null
+++ b/src/Fusillade.Tests/Http/BaseHttpSchedulerSharedTests.cs
@@ -0,0 +1,18 @@
+// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using System.Net.Http;
+using Punchclock;
+
+namespace Fusillade.Tests
+{
+ public class BaseHttpSchedulerSharedTests : HttpSchedulerSharedTests
+ {
+ protected override LimitingHttpMessageHandler CreateFixture(HttpMessageHandler innerHandler)
+ {
+ return new RateLimitedHttpMessageHandler(innerHandler, Priority.UserInitiated, opQueue: new OperationQueue(4));
+ }
+ }
+}
diff --git a/src/Fusillade.Tests/Http/CachedHttpSchedulerTests.cs b/src/Fusillade.Tests/Http/CachedHttpSchedulerTests.cs
deleted file mode 100644
index c861987..0000000
--- a/src/Fusillade.Tests/Http/CachedHttpSchedulerTests.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-//using System;
-//using System.Collections.Generic;
-//using System.Linq;
-//using System.Net.Http;
-//using System.Text;
-//using System.Reactive;
-//using System.Reactive.Linq;
-//using System.Reactive.Threading.Tasks;
-//using System.Threading.Tasks;
-//using Akavache.Http;
-//using Xunit;
-//using System.IO;
-
-//namespace Akavache.Http.Tests
-//{
-// public class CachedHttpSchedulerTests
-// {
-// [Fact]
-// [Trait("Slow", "Very Yes")]
-// public async Task OurOwnReleaseShouldBeCached()
-// {
-// var input = @"https://github.com/akavache/Akavache/releases/download/3.2.0/Akavache.3.2.0.zip";
-// var blobCache = new TestBlobCache();
-// var fixture = new CachingHttpScheduler(new HttpScheduler(), blobCache);
-
-// fixture.Client = new HttpClient(new HttpClientHandler() {
-// AllowAutoRedirect = true,
-// MaxRequestContentBufferSize = 1048576 * 64,
-// });
-
-// Assert.Equal(0, blobCache.GetAllKeys().First().Count());
-
-// var result = await fixture.Schedule(new HttpRequestMessage(HttpMethod.Get, new Uri(input)), 5);
-
-// Assert.True(result.Item1.IsSuccessStatusCode);
-// Assert.Equal(8089690, result.Item2.Length);
-// Assert.Equal(1, blobCache.GetAllKeys().First().Count());
-
-// var result2 = await fixture.Schedule(new HttpRequestMessage(HttpMethod.Get, new Uri(input)), 3);
-
-// Assert.True(result2.Item1.IsSuccessStatusCode);
-// Assert.Equal(8089690, result2.Item2.Length);
-// }
-
-// [Fact]
-// [Trait("Slow", "Very Yes")]
-// public async Task FailedRequestsShouldntBeCached()
-// {
-// var input = @"https://httpbin.org/status/502";
-// var blobCache = new TestBlobCache();
-// var fixture = new CachingHttpScheduler(new HttpScheduler(), blobCache);
-
-// fixture.Client = new HttpClient(new HttpClientHandler() {
-// AllowAutoRedirect = true,
-// MaxRequestContentBufferSize = 1048576 * 64,
-// });
-
-// Assert.Equal(0, blobCache.GetAllKeys().First().Count());
-
-// var result = await fixture.Schedule(new HttpRequestMessage(HttpMethod.Get, new Uri(input)), 5);
-
-// Assert.Equal(0, blobCache.GetAllKeys().First().Count());
-// Assert.False(result.Item1.IsSuccessStatusCode);
-// }
-
-// [Fact]
-// [Trait("Slow", "Very Yes")]
-// public async Task PostsShouldntBeCached()
-// {
-// var input = @"https://httpbin.org/post";
-// var blobCache = new TestBlobCache();
-// var fixture = new CachingHttpScheduler(new HttpScheduler(), blobCache);
-
-// fixture.Client = new HttpClient(new HttpClientHandler() {
-// AllowAutoRedirect = true,
-// MaxRequestContentBufferSize = 1048576 * 64,
-// });
-
-// Assert.Equal(0, blobCache.GetAllKeys().First().Count());
-
-// var result = await fixture.Schedule(new HttpRequestMessage(HttpMethod.Post, new Uri(input)), 5);
-
-// Assert.Equal(0, blobCache.GetAllKeys().First().Count());
-// Assert.True(result.Item1.IsSuccessStatusCode);
-// }
-
-// [Fact]
-// public async Task PostsWithETagsShouldBeCached()
-// {
-// var input = @"https://httpbin.org/post";
-// var blobCache = new TestBlobCache();
-// var fixture = new CachingHttpScheduler(new HttpScheduler(), blobCache);
-// var requestCount = 0;
-
-// fixture.Client = new HttpClient(new TestHttpMessageHandler(_ => {
-// var response = IntegrationTestHelper.GetResponse("Http", "fixtures", "ResponseWithETag");
-// requestCount++;
-
-// if (requestCount > 1)
-// {
-// // Rig the data to be zero - if we see this, we know we didn't
-// // use the cached version
-// var newData = new ByteArrayContent(new byte[0]);
-// foreach (var kvp in response.Content.Headers) newData.Headers.Add(kvp.Key, kvp.Value);
-// response.Content = newData;
-// }
-
-// return Observable.Return(response);
-// }));
-
-// Assert.Equal(0, blobCache.GetAllKeys().First().Count());
-// Assert.Equal(0, requestCount);
-
-// var result = await fixture.Schedule(new HttpRequestMessage(HttpMethod.Get, new Uri(input)), 5);
-
-// Assert.Equal(1, blobCache.GetAllKeys().First().Count());
-// Assert.Equal(1, requestCount);
-// Assert.True(result.Item2.Length > 0);
-
-// var result2 = await fixture.Schedule(new HttpRequestMessage(HttpMethod.Get, new Uri(input)), 5);
-
-// Assert.Equal(1, blobCache.GetAllKeys().First().Count());
-// Assert.Equal(2, requestCount);
-// Assert.True(result2.Item2.Length > 0);
-// }
-// }
-//}
\ No newline at end of file
diff --git a/src/Fusillade.Tests/Http/HttpSchedulerCachingTests.cs b/src/Fusillade.Tests/Http/HttpSchedulerCachingTests.cs
index 6ffb300..6443940 100644
--- a/src/Fusillade.Tests/Http/HttpSchedulerCachingTests.cs
+++ b/src/Fusillade.Tests/Http/HttpSchedulerCachingTests.cs
@@ -1,4 +1,9 @@
-using Akavache;
+// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using Akavache;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -17,8 +22,10 @@ public class HttpSchedulerCachingTests
[Fact]
public async Task CachingFunctionShouldBeCalledWithContent()
{
- var innerHandler = new TestHttpMessageHandler(_ => {
- var ret = new HttpResponseMessage() {
+ var innerHandler = new TestHttpMessageHandler(_ =>
+ {
+ var ret = new HttpResponseMessage()
+ {
Content = new StringContent("foo", Encoding.UTF8),
StatusCode = HttpStatusCode.OK,
};
@@ -28,12 +35,10 @@ public async Task CachingFunctionShouldBeCalledWithContent()
});
var contentResponses = new List();
- var fixture = new RateLimitedHttpMessageHandler(innerHandler, Priority.UserInitiated, cacheResultFunc: async (rq, re, key, ct) => {
- contentResponses.Add(await re.Content.ReadAsByteArrayAsync());
- });
+ var fixture = new RateLimitedHttpMessageHandler(innerHandler, Priority.UserInitiated, cacheResultFunc: async (rq, re, key, ct) => contentResponses.Add(await re.Content.ReadAsByteArrayAsync().ConfigureAwait(false)));
var client = new HttpClient(fixture);
- var str = await client.GetStringAsync("http://lol/bar");
+ var str = await client.GetStringAsync(new Uri("http://lol/bar")).ConfigureAwait(false);
Assert.Equal("foo", str);
Assert.Equal(1, contentResponses.Count);
@@ -43,8 +48,10 @@ public async Task CachingFunctionShouldBeCalledWithContent()
[Fact]
public async Task CachingFunctionShouldPreserveHeaders()
{
- var innerHandler = new TestHttpMessageHandler(_ => {
- var ret = new HttpResponseMessage() {
+ var innerHandler = new TestHttpMessageHandler(_ =>
+ {
+ var ret = new HttpResponseMessage()
+ {
Content = new StringContent("foo", Encoding.UTF8),
StatusCode = HttpStatusCode.OK,
};
@@ -54,13 +61,14 @@ public async Task CachingFunctionShouldPreserveHeaders()
});
var etagResponses = new List();
- var fixture = new RateLimitedHttpMessageHandler(innerHandler, Priority.UserInitiated, cacheResultFunc: (rq, re, key, ct) => {
+ var fixture = new RateLimitedHttpMessageHandler(innerHandler, Priority.UserInitiated, cacheResultFunc: (rq, re, key, ct) =>
+ {
etagResponses.Add(re.Headers.ETag.Tag);
return Task.FromResult(true);
});
var client = new HttpClient(fixture);
- var resp = await client.GetAsync("http://lol/bar");
+ var resp = await client.GetAsync(new Uri("http://lol/bar")).ConfigureAwait(false);
Assert.Equal("\"worifjw\"", etagResponses[0]);
}
@@ -69,30 +77,32 @@ public async Task RoundTripIntegrationTest()
{
var cache = new InMemoryBlobCache();
- var cachingHandler = new RateLimitedHttpMessageHandler(new HttpClientHandler(), Priority.UserInitiated, cacheResultFunc: async (rq, resp, key, ct) => {
- var data = await resp.Content.ReadAsByteArrayAsync();
+ var cachingHandler = new RateLimitedHttpMessageHandler(new HttpClientHandler(), Priority.UserInitiated, cacheResultFunc: async (rq, resp, key, ct) =>
+ {
+ var data = await resp.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
await cache.Insert(key, data);
});
var client = new HttpClient(cachingHandler);
- var origData = await client.GetStringAsync("http://httpbin.org/get");
+ var origData = await client.GetStringAsync(new Uri("http://httpbin.org/get")).ConfigureAwait(false);
Assert.True(origData.Contains("origin"));
Assert.Equal(1, (await cache.GetAllKeys()).Count());
- var offlineHandler = new OfflineHttpMessageHandler(async (rq, key, ct) => {
- return await cache.Get(key);
- });
+ var offlineHandler = new OfflineHttpMessageHandler(async (rq, key, ct) => await cache.Get(key));
client = new HttpClient(offlineHandler);
- var newData = await client.GetStringAsync("http://httpbin.org/get");
+ var newData = await client.GetStringAsync(new Uri("http://httpbin.org/get")).ConfigureAwait(false);
Assert.Equal(origData, newData);
bool shouldDie = true;
- try {
- await client.GetStringAsync("http://httpbin.org/gzip");
- } catch (Exception ex) {
+ try
+ {
+ await client.GetStringAsync(new Uri("http://httpbin.org/gzip")).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
shouldDie = false;
Console.WriteLine(ex);
}
@@ -110,7 +120,8 @@ public async Task RoundTripIntegrationTest()
[InlineData("WHATEVER", false)]
public async Task OnlyCacheRelevantMethods(string method, bool shouldCache)
{
- var innerHandler = new TestHttpMessageHandler(_ => {
+ var innerHandler = new TestHttpMessageHandler(_ =>
+ {
var ret = new HttpResponseMessage()
{
Content = new StringContent("foo", Encoding.UTF8),
@@ -121,14 +132,15 @@ public async Task OnlyCacheRelevantMethods(string method, bool shouldCache)
});
var cached = false;
- var fixture = new RateLimitedHttpMessageHandler(innerHandler, Priority.UserInitiated, cacheResultFunc: (rq, re, key, ct) => {
+ var fixture = new RateLimitedHttpMessageHandler(innerHandler, Priority.UserInitiated, cacheResultFunc: (rq, re, key, ct) =>
+ {
cached = true;
return Task.FromResult(true);
});
var client = new HttpClient(fixture);
var request = new HttpRequestMessage(new HttpMethod(method), "http://lol/bar");
- await client.SendAsync(request);
+ await client.SendAsync(request).ConfigureAwait(false);
Assert.Equal(shouldCache, cached);
}
diff --git a/src/Fusillade.Tests/Http/HttpSchedulerSharedTests.cs b/src/Fusillade.Tests/Http/HttpSchedulerSharedTests.cs
index eac4fdc..4b56808 100644
--- a/src/Fusillade.Tests/Http/HttpSchedulerSharedTests.cs
+++ b/src/Fusillade.Tests/Http/HttpSchedulerSharedTests.cs
@@ -1,19 +1,24 @@
-using System;
+// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reactive;
+using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Reactive.Threading.Tasks;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using Fusillade;
+using DynamicData;
using Microsoft.Reactive.Testing;
-using Punchclock;
using ReactiveUI;
using ReactiveUI.Testing;
using Xunit;
@@ -22,22 +27,23 @@ namespace Fusillade.Tests
{
public abstract class HttpSchedulerSharedTests
{
- protected abstract LimitingHttpMessageHandler CreateFixture(HttpMessageHandler innerHandler = null);
-
[Fact]
public async Task HttpSchedulerShouldCompleteADummyRequest()
{
- var fixture = CreateFixture(new TestHttpMessageHandler(_ => {
- var ret = new HttpResponseMessage() {
+ var fixture = CreateFixture(new TestHttpMessageHandler(_ =>
+ {
+ var ret = new HttpResponseMessage()
+ {
Content = new StringContent("foo", Encoding.UTF8),
StatusCode = HttpStatusCode.OK,
};
-
+
ret.Headers.ETag = new EntityTagHeaderValue("\"worifjw\"");
return Observable.Return(ret);
}));
- var client = new HttpClient(fixture) {
+ var client = new HttpClient(fixture)
+ {
BaseAddress = new Uri("http://example"),
};
@@ -46,7 +52,7 @@ public async Task HttpSchedulerShouldCompleteADummyRequest()
var result = await client.SendAsync(rq).ToObservable()
.Timeout(TimeSpan.FromSeconds(2.0), RxApp.TaskpoolScheduler);
- var bytes = await result.Content.ReadAsByteArrayAsync();
+ var bytes = await result.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
Console.WriteLine(Encoding.UTF8.GetString(bytes));
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
@@ -60,9 +66,11 @@ public void HttpSchedulerShouldntScheduleLotsOfStuffAtOnce()
var scheduledCount = default(int);
var completedCount = default(int);
- var fixture = CreateFixture(new TestHttpMessageHandler(rq => {
+ var fixture = CreateFixture(new TestHttpMessageHandler(rq =>
+ {
scheduledCount++;
- var ret = new HttpResponseMessage() {
+ var ret = new HttpResponseMessage()
+ {
Content = new StringContent("foo", Encoding.UTF8),
StatusCode = HttpStatusCode.OK,
};
@@ -76,31 +84,38 @@ public void HttpSchedulerShouldntScheduleLotsOfStuffAtOnce()
var client = new HttpClient(fixture);
client.BaseAddress = new Uri("http://example");
- (new TestScheduler()).With(sched => {
+ new TestScheduler().With(sched =>
+ {
var rqs = Enumerable.Range(0, 5)
.Select(x => new HttpRequestMessage(HttpMethod.Get, "/" + x.ToString()))
.ToArray();
- var results = rqs.ToObservable()
+ rqs.ToObservable()
.Select(rq => client.SendAsync(rq))
.Merge()
- .CreateCollection();
+ .ToObservableChangeSet()
+ .ObserveOn(ImmediateScheduler.Instance)
+ .Bind(out var results)
+ .Subscribe();
sched.Start();
-
+
Assert.Equal(4, scheduledCount);
Assert.Equal(0, completedCount);
var firstSubj = blockedRqs.First().Value;
- firstSubj.OnNext(Unit.Default); firstSubj.OnCompleted();
+ firstSubj.OnNext(Unit.Default);
+ firstSubj.OnCompleted();
sched.Start();
Assert.Equal(5, scheduledCount);
Assert.Equal(1, completedCount);
- foreach (var v in blockedRqs.Values) {
- v.OnNext(Unit.Default); v.OnCompleted();
+ foreach (var v in blockedRqs.Values)
+ {
+ v.OnNext(Unit.Default);
+ v.OnCompleted();
}
sched.Start();
@@ -113,17 +128,20 @@ public void HttpSchedulerShouldntScheduleLotsOfStuffAtOnce()
[Fact]
public async Task RateLimitedSchedulerShouldStopAfterContentLimitReached()
{
- var fixture = CreateFixture(new TestHttpMessageHandler(_ => {
- var ret = new HttpResponseMessage() {
+ var fixture = CreateFixture(new TestHttpMessageHandler(_ =>
+ {
+ var ret = new HttpResponseMessage()
+ {
Content = new StringContent("foo", Encoding.UTF8),
StatusCode = HttpStatusCode.OK,
};
-
+
ret.Headers.ETag = new EntityTagHeaderValue("\"worifjw\"");
return Observable.Return(ret);
}));
- var client = new HttpClient(fixture) {
+ var client = new HttpClient(fixture)
+ {
BaseAddress = new Uri("http://example"),
};
@@ -131,17 +149,17 @@ public async Task RateLimitedSchedulerShouldStopAfterContentLimitReached()
// Under the limit => succeed
var rq = new HttpRequestMessage(HttpMethod.Get, "/");
- var resp = await client.SendAsync(rq);
+ var resp = await client.SendAsync(rq).ConfigureAwait(false);
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
// Crossing the limit => succeed
rq = new HttpRequestMessage(HttpMethod.Get, "/");
- resp = await client.SendAsync(rq);
+ resp = await client.SendAsync(rq).ConfigureAwait(false);
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
// Over the limit => cancelled
rq = new HttpRequestMessage(HttpMethod.Get, "/");
- await Assert.ThrowsAsync(() => client.SendAsync(rq));
+ await Assert.ThrowsAsync(() => client.SendAsync(rq)).ConfigureAwait(false);
}
[Fact]
@@ -150,19 +168,22 @@ public async Task ConcurrentRequestsToTheSameResourceAreDebounced()
int messageCount = 0;
Subject gate = new Subject();
- var fixture = CreateFixture(new TestHttpMessageHandler(_ => {
- var ret = new HttpResponseMessage() {
+ var fixture = CreateFixture(new TestHttpMessageHandler(_ =>
+ {
+ var ret = new HttpResponseMessage()
+ {
Content = new StringContent("foo", Encoding.UTF8),
StatusCode = HttpStatusCode.OK,
};
-
+
ret.Headers.ETag = new EntityTagHeaderValue("\"worifjw\"");
messageCount++;
return gate.Take(1).Select(__ => ret);
}));
- var client = new HttpClient(fixture) {
+ var client = new HttpClient(fixture)
+ {
BaseAddress = new Uri("http://example"),
};
@@ -192,19 +213,22 @@ public async Task DebouncedRequestsDontGetUnfairlyCancelled()
int messageCount = 0;
Subject gate = new Subject();
- var fixture = CreateFixture(new TestHttpMessageHandler(_ => {
- var ret = new HttpResponseMessage() {
+ var fixture = CreateFixture(new TestHttpMessageHandler(_ =>
+ {
+ var ret = new HttpResponseMessage()
+ {
Content = new StringContent("foo", Encoding.UTF8),
StatusCode = HttpStatusCode.OK,
};
-
+
ret.Headers.ETag = new EntityTagHeaderValue("\"worifjw\"");
messageCount++;
return gate.Take(1).Select(__ => ret);
}));
- var client = new HttpClient(fixture) {
+ var client = new HttpClient(fixture)
+ {
BaseAddress = new Uri("http://example"),
};
@@ -214,10 +238,10 @@ public async Task DebouncedRequestsDontGetUnfairlyCancelled()
Assert.Equal(0, messageCount);
/* NB: Here's the thing we're testing for
- *
+ *
* When we issue concurrent requests to the same resource, one of them
* will actually do the request, and one of them will wait on the other.
- * In this case, rq1 will do the request, and rq2 will just return
+ * In this case, rq1 will do the request, and rq2 will just return
* whatever rq1 will return.
*
* The key then, is to only truly cancel rq1 if both rq1 *and* rq2
@@ -233,7 +257,7 @@ public async Task DebouncedRequestsDontGetUnfairlyCancelled()
gate.OnNext(Unit.Default);
gate.OnNext(Unit.Default);
- await Assert.ThrowsAsync(() => resp1Task);
+ await Assert.ThrowsAsync(() => resp1Task).ConfigureAwait(false);
var resp2 = await resp2Task;
Assert.Equal(HttpStatusCode.OK, resp2.StatusCode);
@@ -246,19 +270,22 @@ public async Task RequestsToDifferentPathsArentDebounced()
int messageCount = 0;
Subject gate = new Subject();
- var fixture = CreateFixture(new TestHttpMessageHandler(_ => {
- var ret = new HttpResponseMessage() {
+ var fixture = CreateFixture(new TestHttpMessageHandler(_ =>
+ {
+ var ret = new HttpResponseMessage()
+ {
Content = new StringContent("foo", Encoding.UTF8),
StatusCode = HttpStatusCode.OK,
};
-
+
ret.Headers.ETag = new EntityTagHeaderValue("\"worifjw\"");
messageCount++;
return gate.Take(1).Select(__ => ret);
}));
- var client = new HttpClient(fixture) {
+ var client = new HttpClient(fixture)
+ {
BaseAddress = new Uri("http://example"),
};
@@ -282,8 +309,6 @@ public async Task RequestsToDifferentPathsArentDebounced()
Assert.Equal(2, messageCount);
}
-
-
[Fact]
public async Task FullyCancelledDebouncedRequestsGetForRealCancelled()
{
@@ -291,12 +316,14 @@ public async Task FullyCancelledDebouncedRequestsGetForRealCancelled()
int finalMessageCount = 0;
Subject gate = new Subject();
- var fixture = CreateFixture(new TestHttpMessageHandler(_ => {
- var ret = new HttpResponseMessage() {
+ var fixture = CreateFixture(new TestHttpMessageHandler(_ =>
+ {
+ var ret = new HttpResponseMessage()
+ {
Content = new StringContent("foo", Encoding.UTF8),
StatusCode = HttpStatusCode.OK,
};
-
+
ret.Headers.ETag = new EntityTagHeaderValue("\"worifjw\"");
messageCount++;
@@ -305,7 +332,8 @@ public async Task FullyCancelledDebouncedRequestsGetForRealCancelled()
.Select(__ => ret);
}));
- var client = new HttpClient(fixture) {
+ var client = new HttpClient(fixture)
+ {
BaseAddress = new Uri("http://example"),
};
@@ -315,15 +343,15 @@ public async Task FullyCancelledDebouncedRequestsGetForRealCancelled()
Assert.Equal(0, messageCount);
/* NB: Here's the thing we're testing for
- *
+ *
* When we issue concurrent requests to the same resource, one of them
* will actually do the request, and one of them will wait on the other.
- * In this case, rq1 will do the request, and rq2 will just return
+ * In this case, rq1 will do the request, and rq2 will just return
* whatever rq1 will return.
*
* The key then, is to only truly cancel rq1 if both rq1 *and* rq2
* are cancelled, but rq1 should *appear* to be cancelled. This test
- * cancels both requests then makes sure we actually cancel the
+ * cancels both requests then makes sure we actually cancel the
* underlying result */
var cts = new CancellationTokenSource();
@@ -337,122 +365,32 @@ public async Task FullyCancelledDebouncedRequestsGetForRealCancelled()
gate.OnNext(Unit.Default);
gate.OnNext(Unit.Default);
- await Assert.ThrowsAsync(() => resp1Task);
- await Assert.ThrowsAsync(() => resp2Task);
+ await Assert.ThrowsAsync(() => resp1Task).ConfigureAwait(false);
+ await Assert.ThrowsAsync(() => resp2Task).ConfigureAwait(false);
Assert.Equal(1, messageCount);
Assert.Equal(0, finalMessageCount);
}
-
- /*
- [Fact]
- public void CancelAllShouldCancelAllInflightRequests()
- {
- // NB: This is intentionally picked to be under the OperationQueue's
- // default concurrency limit of 4
- var resps = Enumerable.Range(0, 3)
- .Select(_ => new AsyncSubject())
- .ToArray();
-
- var currentResp = 0;
- var client = new HttpClient(new TestHttpMessageHandler(_ =>
- resps[(currentResp++) % resps.Length]));
-
- var fixture = CreateFixture();
- fixture.Client = client;
-
- Assert.True(resps.All(x => x.HasObservers == false));
-
- fixture.ScheduleAll(sched =>
- {
- resps.ToObservable()
- .SelectMany(_ =>
- sched.Schedule(new HttpRequestMessage(HttpMethod.Get, new Uri("http://example/" + Guid.NewGuid())), 3))
- .Subscribe();
- });
-
- Assert.True(resps.All(x => x.HasObservers == true));
-
- fixture.CancelAll();
-
- Assert.True(resps.All(x => x.HasObservers == false));
- }
- */
-
- /*
- * HttpSchedulerExtensions
- */
-
- /*
- [Fact]
- public void ScheduleAllShouldLetUsCancelEverything()
- {
- // NB: This is intentionally picked to be under the OperationQueue's
- // default concurrency limit of 4
- var resps = Enumerable.Range(0, 3)
- .Select(_ => new AsyncSubject())
- .ToArray();
-
- var currentResp = 0;
- var client = new HttpClient(new TestHttpMessageHandler(_ =>
- resps[(currentResp++) % resps.Length]));
-
- var fixture = CreateFixture();
- fixture.Client = client;
-
- Assert.True(resps.All(x => x.HasObservers == false));
-
- var disp = fixture.ScheduleAll(sched =>
- {
- resps.ToObservable()
- .SelectMany(_ =>
- sched.Schedule(new HttpRequestMessage(HttpMethod.Get, new Uri("http://example/" + Guid.NewGuid())), 3))
- .Subscribe();
- });
-
- Assert.True(resps.All(x => x.HasObservers == true));
-
- disp.Dispose();
-
- Assert.True(resps.All(x => x.HasObservers == false));
- }
- */
-
[Fact]
[Trait("Slow", "Very Yes")]
public async Task DownloadARelease()
{
var input = @"https://github.com/akavache/Akavache/releases/download/3.2.0/Akavache.3.2.0.zip";
- var fixture = CreateFixture(new HttpClientHandler() {
+ var fixture = CreateFixture(new HttpClientHandler()
+ {
AllowAutoRedirect = true,
MaxRequestContentBufferSize = 1048576 * 64,
});
var client = new HttpClient(fixture);
- var result = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, new Uri(input)));
- var bytes = await result.Content.ReadAsByteArrayAsync();
+ var result = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, new Uri(input))).ConfigureAwait(false);
+ var bytes = await result.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
Assert.True(result.IsSuccessStatusCode);
Assert.Equal(8089690, bytes.Length);
}
- }
- public class BaseHttpSchedulerSharedTests : HttpSchedulerSharedTests
- {
- protected override LimitingHttpMessageHandler CreateFixture(HttpMessageHandler innerHandler)
- {
- return new RateLimitedHttpMessageHandler(innerHandler, Priority.UserInitiated, opQueue: new OperationQueue(4));
- }
- }
-
- /*
- public class CachingHttpSchedulerSharedTests : HttpSchedulerSharedTests
- {
- protected override IHttpScheduler CreateFixture()
- {
- return new CachingHttpScheduler(new HttpScheduler(opQueue: new OperationQueue(4)), new TestBlobCache());
- }
+ protected abstract LimitingHttpMessageHandler CreateFixture(HttpMessageHandler innerHandler = null);
}
- */
}
diff --git a/src/Fusillade.Tests/Http/TestHttpMessageHandler.cs b/src/Fusillade.Tests/Http/TestHttpMessageHandler.cs
index 8c3183d..7b3a27e 100644
--- a/src/Fusillade.Tests/Http/TestHttpMessageHandler.cs
+++ b/src/Fusillade.Tests/Http/TestHttpMessageHandler.cs
@@ -1,21 +1,24 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using System;
using System.Threading.Tasks;
using System.Net.Http;
using System.Threading;
using System.Reactive.Threading.Tasks;
using System.Reactive.Linq;
-
+
namespace Fusillade.Tests
{
public class TestHttpMessageHandler : HttpMessageHandler
{
- Func> block;
+ private Func> _block;
+
public TestHttpMessageHandler(Func> createResult)
{
- block = createResult;
+ _block = createResult;
}
protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
@@ -25,7 +28,7 @@ protected override Task SendAsync(HttpRequestMessage reques
return Observable.Throw(new OperationCanceledException()).ToTask();
}
- return block(request).ToTask(cancellationToken);
+ return _block(request).ToTask(cancellationToken);
}
}
}
\ No newline at end of file
diff --git a/src/Fusillade.Tests/IntegrationTestHelper.cs b/src/Fusillade.Tests/IntegrationTestHelper.cs
index 95f5d0e..42eed57 100644
--- a/src/Fusillade.Tests/IntegrationTestHelper.cs
+++ b/src/Fusillade.Tests/IntegrationTestHelper.cs
@@ -1,15 +1,15 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
+// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
-using System.Reactive;
-using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Text;
-using System.Threading;
namespace Fusillade.Tests
{
@@ -18,7 +18,7 @@ public static class IntegrationTestHelper
public static string GetPath(params string[] paths)
{
var ret = GetIntegrationTestRootDirectory();
- return (new FileInfo(paths.Aggregate(ret, Path.Combine))).FullName;
+ return new FileInfo(paths.Aggregate(ret, Path.Combine)).FullName;
}
public static string GetIntegrationTestRootDirectory()
@@ -26,7 +26,6 @@ public static string GetIntegrationTestRootDirectory()
// XXX: This is an evil hack, but it's okay for a unit test
// We can't use Assembly.Location because unit test runners love
// to move stuff to temp directories
-
return Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName;
}
@@ -53,7 +52,7 @@ public static HttpResponseMessage GetResponse(params string[] paths)
var headerText = Encoding.UTF8.GetString(bytes, 0, bodyIndex);
var lines = headerText.Split('\n');
- var statusCode = (HttpStatusCode)Int32.Parse(lines[0].Split(' ')[1]);
+ var statusCode = (HttpStatusCode)int.Parse(lines[0].Split(' ')[1]);
var ret = new HttpResponseMessage(statusCode);
ret.Content = new ByteArrayContent(bytes, bodyIndex + 2, bytes.Length - bodyIndex - 2);
@@ -64,7 +63,10 @@ public static HttpResponseMessage GetResponse(params string[] paths)
var key = line.Substring(0, separatorIndex);
var val = line.Substring(separatorIndex + 2).TrimEnd();
- if (String.IsNullOrWhiteSpace(line)) continue;
+ if (string.IsNullOrWhiteSpace(line))
+ {
+ continue;
+ }
ret.Headers.TryAddWithoutValidation(key, val);
ret.Content.Headers.TryAddWithoutValidation(key, val);
diff --git a/src/Fusillade.Tests/Properties/AssemblyInfo.cs b/src/Fusillade.Tests/Properties/AssemblyInfo.cs
deleted file mode 100644
index cfdadba..0000000
--- a/src/Fusillade.Tests/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Fusillade.Tests")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Fusillade.Tests")]
-[assembly: AssemblyCopyright("Copyright © 2017")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("ba0745e4-4566-4655-b83c-b4398f67dc39")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/Fusillade/ConcatenateMixin.cs b/src/Fusillade/ConcatenateMixin.cs
new file mode 100644
index 0000000..e84c499
--- /dev/null
+++ b/src/Fusillade/ConcatenateMixin.cs
@@ -0,0 +1,25 @@
+// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reactive.Linq;
+using System.Text;
+
+namespace Fusillade
+{
+ internal static class ConcatenateMixin
+ {
+ public static string ConcatenateAll(this IEnumerable enumerables, Func selector, char separator = '|')
+ {
+ return enumerables.Aggregate(new StringBuilder(), (acc, x) =>
+ {
+ acc.Append(selector(x)).Append(separator);
+ return acc;
+ }).ToString();
+ }
+ }
+}
diff --git a/src/Fusillade/Fusillade.csproj b/src/Fusillade/Fusillade.csproj
index 721a373..871b670 100644
--- a/src/Fusillade/Fusillade.csproj
+++ b/src/Fusillade/Fusillade.csproj
@@ -1,24 +1,13 @@
-
-
+
-
-
-
- netstandard1.4
+ netstandard2.0
fusillade
- An HttpClient implementation for mobile apps that efficiently schedules and prioritizes requests
- https://avatars0.githubusercontent.com/u/5924219?v=3&s=200
-
- https://opensource.org/licenses/MIT
- Copyright (c) Paul Betts
- fusillade, cache, xamarin
- https://github.com/paulcbetts/Fusillade
-
-
-
+
+
+
+
-
diff --git a/src/Fusillade/IRequestCache.cs b/src/Fusillade/IRequestCache.cs
new file mode 100644
index 0000000..d0c5aa0
--- /dev/null
+++ b/src/Fusillade/IRequestCache.cs
@@ -0,0 +1,42 @@
+// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Fusillade
+{
+ ///
+ /// This Interface is a simple cache for HTTP requests - it is intentionally
+ /// *not* designed to conform to HTTP caching rules since you most likely want
+ /// to override those rules in a client app anyways.
+ ///
+ public interface IRequestCache
+ {
+ ///
+ /// Implement this method by saving the Body of the response. The
+ /// response is already downloaded as a ByteArrayContent so you don't
+ /// have to worry about consuming the stream.
+ ///
+ /// The originating request.
+ /// The response whose body you should save.
+ /// A unique key used to identify the request details.
+ /// Cancellation token.
+ /// Completion.
+ Task Save(HttpRequestMessage request, HttpResponseMessage response, string key, CancellationToken ct);
+
+ ///
+ /// Implement this by loading the Body of the given request / key.
+ ///
+ /// The originating request.
+ /// A unique key used to identify the request details,
+ /// that was given in Save().
+ /// Cancellation token.
+ /// The Body of the given request, or null if the search
+ /// completed successfully but the response was not found.
+ Task Fetch(HttpRequestMessage request, string key, CancellationToken ct);
+ }
+}
\ No newline at end of file
diff --git a/src/Fusillade/InflightRequest.cs b/src/Fusillade/InflightRequest.cs
new file mode 100644
index 0000000..f7c7816
--- /dev/null
+++ b/src/Fusillade/InflightRequest.cs
@@ -0,0 +1,39 @@
+// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using System;
+using System.Net.Http;
+using System.Reactive.Subjects;
+using System.Threading;
+
+namespace Fusillade
+{
+ internal class InflightRequest
+ {
+ private int _refCount = 1;
+ private Action _onCancelled;
+
+ public InflightRequest(Action onFullyCancelled)
+ {
+ _onCancelled = onFullyCancelled;
+ Response = new AsyncSubject();
+ }
+
+ public AsyncSubject Response { get; protected set; }
+
+ public void AddRef()
+ {
+ Interlocked.Increment(ref _refCount);
+ }
+
+ public void Cancel()
+ {
+ if (Interlocked.Decrement(ref _refCount) <= 0)
+ {
+ _onCancelled();
+ }
+ }
+ }
+}
diff --git a/src/Fusillade/Interfaces.cs b/src/Fusillade/Interfaces.cs
deleted file mode 100644
index 6a4c2d6..0000000
--- a/src/Fusillade/Interfaces.cs
+++ /dev/null
@@ -1,209 +0,0 @@
-using System;
-using System.Net.Http;
-using Punchclock;
-using Splat;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Fusillade
-{
- ///
- /// This enumeration defines the default base priorities associated with the
- /// different NetCache instances
- ///
- public enum Priority {
- Speculative = 10,
- UserInitiated = 100,
- Background = 20,
- Explicit = 0,
- }
-
- ///
- /// Limiting HTTP schedulers only allow a certain number of bytes to be
- /// read before cancelling all future requests. This is designed for
- /// reading data that may or may not be used by the user later, in order
- /// to improve response times should the user later request the data.
- ///
- public abstract class LimitingHttpMessageHandler : DelegatingHandler
- {
- public LimitingHttpMessageHandler(HttpMessageHandler innerHandler) : base(innerHandler) { }
- public LimitingHttpMessageHandler() : base() { }
-
- ///
- /// Resets the total limit of bytes to read. This is usually called
- /// when the app resumes from suspend, to indicate that we should
- /// fetch another set of data.
- ///
- ///
- public abstract void ResetLimit(long? maxBytesToRead = null);
- }
-
- ///
- /// This Interface is a simple cache for HTTP requests - it is intentionally
- /// *not* designed to conform to HTTP caching rules since you most likely want
- /// to override those rules in a client app anyways.
- ///
- public interface IRequestCache
- {
- ///
- /// Implement this method by saving the Body of the response. The
- /// response is already downloaded as a ByteArrayContent so you don't
- /// have to worry about consuming the stream.
- ///
- /// The originating request.
- /// The response whose body you should save.
- /// A unique key used to identify the request details.
- /// Cancellation token.
- /// Completion.
- Task Save(HttpRequestMessage request, HttpResponseMessage response, string key, CancellationToken ct);
-
- ///
- /// Implement this by loading the Body of the given request / key.
- ///
- /// The originating request.
- /// A unique key used to identify the request details,
- /// that was given in Save().
- /// Cancellation token.
- /// The Body of the given request, or null if the search
- /// completed successfully but the response was not found.
- Task Fetch(HttpRequestMessage request, string key, CancellationToken ct);
- }
-
- public static class NetCache
- {
- static NetCache()
- {
- var innerHandler = Locator.Current.GetService() ?? new HttpClientHandler();
-
- // NB: In vNext this value will be adjusted based on the user's
- // network connection, but that requires us to go fully platformy
- // like Splat.
- speculative = new RateLimitedHttpMessageHandler(innerHandler, Priority.Speculative, 0, 1048576 * 5);
- userInitiated = new RateLimitedHttpMessageHandler(innerHandler, Priority.UserInitiated, 0);
- background = new RateLimitedHttpMessageHandler(innerHandler, Priority.Background, 0);
- offline = new OfflineHttpMessageHandler(null);
- }
-
- static LimitingHttpMessageHandler speculative;
- [ThreadStatic] static LimitingHttpMessageHandler unitTestSpeculative;
-
- ///
- /// Speculative HTTP schedulers only allow a certain number of bytes to be
- /// read before cancelling all future requests. This is designed for
- /// reading data that may or may not be used by the user later, in order
- /// to improve response times should the user later request the data.
- ///
- public static LimitingHttpMessageHandler Speculative
- {
- get { return unitTestSpeculative ?? speculative ?? Locator.Current.GetService("Speculative"); }
- set {
- if (ModeDetector.InUnitTestRunner()) {
- unitTestSpeculative = value;
- speculative = speculative ?? value;
- } else {
- speculative = value;
- }
- }
- }
-
- static HttpMessageHandler userInitiated;
- [ThreadStatic] static HttpMessageHandler unitTestUserInitiated;
-
- ///
- /// This scheduler should be used for requests initiated by a user
- /// action such as clicking an item, they have the highest priority.
- ///
- public static HttpMessageHandler UserInitiated
- {
- get { return unitTestUserInitiated ?? userInitiated ?? Locator.Current.GetService("UserInitiated"); }
- set {
- if (ModeDetector.InUnitTestRunner()) {
- unitTestUserInitiated = value;
- userInitiated = userInitiated ?? value;
- } else {
- userInitiated = value;
- }
- }
- }
-
- static HttpMessageHandler background;
- [ThreadStatic] static HttpMessageHandler unitTestBackground;
-
- ///
- /// This scheduler should be used for requests initiated in the
- /// background, and are scheduled at a lower priority.
- ///
- public static HttpMessageHandler Background
- {
- get { return unitTestBackground ?? background ?? Locator.Current.GetService("Background"); }
- set {
- if (ModeDetector.InUnitTestRunner()) {
- unitTestBackground = value;
- background = background ?? value;
- } else {
- background = value;
- }
- }
- }
-
- static HttpMessageHandler offline;
- [ThreadStatic] static HttpMessageHandler unitTestOffline;
-
- ///
- /// This scheduler fetches results solely from the cache specified in
- /// RequestCache.
- ///
- public static HttpMessageHandler Offline {
- get { return unitTestOffline ?? offline ?? Locator.Current.GetService("Offline"); }
- set {
- if (ModeDetector.InUnitTestRunner()) {
- unitTestOffline = value;
- offline = offline ?? value;
- } else {
- offline = value;
- }
- }
- }
-
- static OperationQueue operationQueue = new OperationQueue(4);
- [ThreadStatic] static OperationQueue unitTestOperationQueue;
-
- ///
- /// This scheduler should be used for requests initiated in the
- /// operationQueue, and are scheduled at a lower priority. You don't
- /// need to mess with this.
- ///
- public static OperationQueue OperationQueue
- {
- get { return unitTestOperationQueue ?? operationQueue ?? Locator.Current.GetService("OperationQueue"); }
- set {
- if (ModeDetector.InUnitTestRunner()) {
- unitTestOperationQueue = value;
- operationQueue = operationQueue ?? value;
- } else {
- operationQueue = value;
- }
- }
- }
-
- static IRequestCache requestCache;
- [ThreadStatic] static IRequestCache unitTestRequestCache;
-
- ///
- /// If set, this indicates that HTTP handlers should save and load
- /// requests from a cached source.
- ///
- public static IRequestCache RequestCache
- {
- get { return unitTestRequestCache ?? requestCache; }
- set {
- if (ModeDetector.InUnitTestRunner()) {
- unitTestRequestCache = value;
- requestCache = requestCache ?? value;
- } else {
- requestCache = value;
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/Fusillade/LimitingHttpMessageHandler.cs b/src/Fusillade/LimitingHttpMessageHandler.cs
new file mode 100644
index 0000000..29e82fa
--- /dev/null
+++ b/src/Fusillade/LimitingHttpMessageHandler.cs
@@ -0,0 +1,42 @@
+// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using System.Net.Http;
+
+namespace Fusillade
+{
+ ///
+ /// Limiting HTTP schedulers only allow a certain number of bytes to be
+ /// read before cancelling all future requests. This is designed for
+ /// reading data that may or may not be used by the user later, in order
+ /// to improve response times should the user later request the data.
+ ///
+ public abstract class LimitingHttpMessageHandler : DelegatingHandler
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A inner handler we will call to get the data.
+ public LimitingHttpMessageHandler(HttpMessageHandler innerHandler)
+ : base(innerHandler)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public LimitingHttpMessageHandler()
+ {
+ }
+
+ ///
+ /// Resets the total limit of bytes to read. This is usually called
+ /// when the app resumes from suspend, to indicate that we should
+ /// fetch another set of data.
+ ///
+ /// The maximum number of bytes to read.
+ public abstract void ResetLimit(long? maxBytesToRead = null);
+ }
+}
\ No newline at end of file
diff --git a/src/Fusillade/NetCache.cs b/src/Fusillade/NetCache.cs
new file mode 100644
index 0000000..14d4199
--- /dev/null
+++ b/src/Fusillade/NetCache.cs
@@ -0,0 +1,182 @@
+// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using System;
+using System.Net.Http;
+using Punchclock;
+using Splat;
+
+namespace Fusillade
+{
+ ///
+ /// Handles caching for our Http requests.
+ ///
+ public static class NetCache
+ {
+ private static LimitingHttpMessageHandler speculative;
+ [ThreadStatic]
+ private static LimitingHttpMessageHandler unitTestSpeculative;
+ private static HttpMessageHandler userInitiated;
+ [ThreadStatic]
+ private static HttpMessageHandler unitTestUserInitiated;
+ private static HttpMessageHandler background;
+ [ThreadStatic]
+ private static HttpMessageHandler unitTestBackground;
+ private static HttpMessageHandler offline;
+ [ThreadStatic]
+ private static HttpMessageHandler unitTestOffline;
+ private static OperationQueue operationQueue = new OperationQueue(4);
+ [ThreadStatic]
+ private static OperationQueue unitTestOperationQueue;
+ private static IRequestCache requestCache;
+ [ThreadStatic]
+ private static IRequestCache unitTestRequestCache;
+
+ ///
+ /// Initializes static members of the class.
+ ///
+ static NetCache()
+ {
+ var innerHandler = Locator.Current.GetService() ?? new HttpClientHandler();
+
+ // NB: In vNext this value will be adjusted based on the user's
+ // network connection, but that requires us to go fully platformy
+ // like Splat.
+ speculative = new RateLimitedHttpMessageHandler(innerHandler, Priority.Speculative, 0, 1048576 * 5);
+ userInitiated = new RateLimitedHttpMessageHandler(innerHandler, Priority.UserInitiated, 0);
+ background = new RateLimitedHttpMessageHandler(innerHandler, Priority.Background, 0);
+ offline = new OfflineHttpMessageHandler(null);
+ }
+
+ ///
+ /// Gets or sets a handler of that allow a certain number of bytes to be
+ /// read before cancelling all future requests. This is designed for
+ /// reading data that may or may not be used by the user later, in order
+ /// to improve response times should the user later request the data.
+ ///
+ public static LimitingHttpMessageHandler Speculative
+ {
+ get => unitTestSpeculative ?? speculative ?? Locator.Current.GetService("Speculative");
+ set
+ {
+ if (ModeDetector.InUnitTestRunner())
+ {
+ unitTestSpeculative = value;
+ speculative = speculative ?? value;
+ }
+ else
+ {
+ speculative = value;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets a scheduler that should be used for requests initiated by a user
+ /// action such as clicking an item, they have the highest priority.
+ ///
+ public static HttpMessageHandler UserInitiated
+ {
+ get => unitTestUserInitiated ?? userInitiated ?? Locator.Current.GetService("UserInitiated");
+ set
+ {
+ if (ModeDetector.InUnitTestRunner())
+ {
+ unitTestUserInitiated = value;
+ userInitiated = userInitiated ?? value;
+ }
+ else
+ {
+ userInitiated = value;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets a scheduler that should be used for requests initiated in the
+ /// background, and are scheduled at a lower priority.
+ ///
+ public static HttpMessageHandler Background
+ {
+ get => unitTestBackground ?? background ?? Locator.Current.GetService("Background");
+ set
+ {
+ if (ModeDetector.InUnitTestRunner())
+ {
+ unitTestBackground = value;
+ background = background ?? value;
+ }
+ else
+ {
+ background = value;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets a scheduler that fetches results solely from the cache specified in
+ /// RequestCache.
+ ///
+ public static HttpMessageHandler Offline
+ {
+ get => unitTestOffline ?? offline ?? Locator.Current.GetService("Offline");
+ set
+ {
+ if (ModeDetector.InUnitTestRunner())
+ {
+ unitTestOffline = value;
+ offline = offline ?? value;
+ }
+ else
+ {
+ offline = value;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets a scheduler that should be used for requests initiated in the
+ /// operationQueue, and are scheduled at a lower priority. You don't
+ /// need to mess with this.
+ ///
+ public static OperationQueue OperationQueue
+ {
+ get => unitTestOperationQueue ?? operationQueue ?? Locator.Current.GetService("OperationQueue");
+ set
+ {
+ if (ModeDetector.InUnitTestRunner())
+ {
+ unitTestOperationQueue = value;
+ operationQueue = operationQueue ?? value;
+ }
+ else
+ {
+ operationQueue = value;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets a request cache that if set indicates that HTTP handlers should save and load
+ /// requests from a cached source.
+ ///
+ public static IRequestCache RequestCache
+ {
+ get => unitTestRequestCache ?? requestCache;
+ set
+ {
+ if (ModeDetector.InUnitTestRunner())
+ {
+ unitTestRequestCache = value;
+ requestCache = requestCache ?? value;
+ }
+ else
+ {
+ requestCache = value;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Fusillade/OfflineHttpMessageHandler.cs b/src/Fusillade/OfflineHttpMessageHandler.cs
index 83e8685..f79ee51 100644
--- a/src/Fusillade/OfflineHttpMessageHandler.cs
+++ b/src/Fusillade/OfflineHttpMessageHandler.cs
@@ -1,37 +1,50 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
+// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using System;
using System.Net;
using System.Net.Http;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Fusillade
{
+ ///
+ /// A http handler that will make a response even if the HttpClient is offline.
+ ///
public class OfflineHttpMessageHandler : HttpMessageHandler
{
- readonly Func> retrieveBody;
+ private readonly Func> _retrieveBody;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A function that will retrieve a body.
public OfflineHttpMessageHandler(Func> retrieveBodyFunc)
{
- retrieveBody = retrieveBodyFunc;
+ _retrieveBody = retrieveBodyFunc;
}
+ ///
protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
- var retrieveBody = this.retrieveBody;
- if (retrieveBody == null && NetCache.RequestCache != null) {
+ var retrieveBody = _retrieveBody;
+ if (retrieveBody == null && NetCache.RequestCache != null)
+ {
retrieveBody = NetCache.RequestCache.Fetch;
}
- if (retrieveBody == null) {
+ if (retrieveBody == null)
+ {
throw new Exception("Configure NetCache.RequestCache before calling this!");
}
- var body = await retrieveBody(request, RateLimitedHttpMessageHandler.UniqueKeyForRequest(request), cancellationToken);
- if (body == null) {
- return new HttpResponseMessage(System.Net.HttpStatusCode.ServiceUnavailable);
+ var body = await retrieveBody(request, RateLimitedHttpMessageHandler.UniqueKeyForRequest(request), cancellationToken).ConfigureAwait(false);
+ if (body == null)
+ {
+ return new HttpResponseMessage(HttpStatusCode.ServiceUnavailable);
}
var byteContent = new ByteArrayContent(body);
diff --git a/src/Fusillade/Priority.cs b/src/Fusillade/Priority.cs
new file mode 100644
index 0000000..9a5da80
--- /dev/null
+++ b/src/Fusillade/Priority.cs
@@ -0,0 +1,34 @@
+// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+namespace Fusillade
+{
+ ///
+ /// This enumeration defines the default base priorities associated with the
+ /// different NetCache instances.
+ ///
+ public enum Priority
+ {
+ ///
+ /// A speculative priority where we aren't sure.
+ ///
+ Speculative = 10,
+
+ ///
+ /// This is a instance which is initiated by the user.
+ ///
+ UserInitiated = 100,
+
+ ///
+ /// This is background based task.
+ ///
+ Background = 20,
+
+ ///
+ /// This is a explicit task.
+ ///
+ Explicit = 0,
+ }
+}
\ No newline at end of file
diff --git a/src/Fusillade/RateLimitedHttpMessageHandler.cs b/src/Fusillade/RateLimitedHttpMessageHandler.cs
index ae40c84..881c12c 100644
--- a/src/Fusillade/RateLimitedHttpMessageHandler.cs
+++ b/src/Fusillade/RateLimitedHttpMessageHandler.cs
@@ -1,11 +1,15 @@
-using System;
+// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reactive.Linq;
-using System.Reactive.Subjects;
using System.Reactive.Threading.Tasks;
using System.Text;
using System.Threading;
@@ -14,64 +18,93 @@
namespace Fusillade
{
- class InflightRequest
+ ///
+ /// A http handler which will limit the rate at which we can read.
+ ///
+ public class RateLimitedHttpMessageHandler : LimitingHttpMessageHandler
{
- int refCount = 1;
- Action onCancelled;
-
- public AsyncSubject Response { get; protected set; }
-
- public InflightRequest(Action onFullyCancelled)
- {
- onCancelled = onFullyCancelled;
- Response = new AsyncSubject();
- }
+ private readonly int _priority;
+ private readonly OperationQueue _opQueue;
+ private readonly Dictionary _inflightResponses =
+ new Dictionary();
- public void AddRef()
+ private readonly Func _cacheResult;
+
+ private long? _maxBytesToRead;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The handler we are wrapping.
+ /// The base priority of the request.
+ /// The priority of the request.
+ /// The maximum number of bytes we can reead.
+ /// The operation queue on which to run the operation.
+ /// A method that is called if we need to get cached results.
+ public RateLimitedHttpMessageHandler(HttpMessageHandler handler, Priority basePriority, int priority = 0, long? maxBytesToRead = null, OperationQueue opQueue = null, Func cacheResultFunc = null)
+ : base(handler)
{
- Interlocked.Increment(ref refCount);
+ _priority = (int)basePriority + priority;
+ _maxBytesToRead = maxBytesToRead;
+ _opQueue = opQueue;
+ _cacheResult = cacheResultFunc;
}
- public void Cancel()
+ ///
+ /// Generates a unique key for for a .
+ /// This assists with the caching.
+ ///
+ /// The request to generate a unique key for.
+ /// The unique key.
+ public static string UniqueKeyForRequest(HttpRequestMessage request)
{
- if (Interlocked.Decrement(ref refCount) <= 0) {
- onCancelled();
+ var ret = new[]
+ {
+ request.RequestUri.ToString(),
+ request.Method.Method,
+ request.Headers.Accept.ConcatenateAll(x => x.CharSet + x.MediaType),
+ request.Headers.AcceptEncoding.ConcatenateAll(x => x.Value),
+ (request.Headers.Referrer ?? new Uri("http://example")).AbsoluteUri,
+ request.Headers.UserAgent.ConcatenateAll(x => (x.Product != null ? x.Product.ToString() : x.Comment)),
+ }.Aggregate(
+ new StringBuilder(),
+ (acc, x) =>
+ {
+ acc.AppendLine(x);
+ return acc;
+ });
+
+ if (request.Headers.Authorization != null)
+ {
+ ret.AppendLine(request.Headers.Authorization.Parameter + request.Headers.Authorization.Scheme);
}
- }
- }
- public class RateLimitedHttpMessageHandler : LimitingHttpMessageHandler
- {
- readonly int priority;
- readonly OperationQueue opQueue;
- readonly Dictionary inflightResponses =
- new Dictionary();
-
- readonly Func cacheResult;
-
- long? maxBytesToRead = null;
+ return "HttpSchedulerCache_" + ret.ToString().GetHashCode().ToString("x", CultureInfo.InvariantCulture);
+ }
- public RateLimitedHttpMessageHandler(HttpMessageHandler handler, Priority basePriority, int priority = 0, long? maxBytesToRead = null, OperationQueue opQueue = null, Func cacheResultFunc = null) : base(handler)
+ ///
+ public override void ResetLimit(long? maxBytesToRead = null)
{
- this.priority = (int)basePriority + priority;
- this.maxBytesToRead = maxBytesToRead;
- this.opQueue = opQueue;
- this.cacheResult = cacheResultFunc;
+ _maxBytesToRead = maxBytesToRead;
}
+ ///
protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var method = request.Method;
- if (method != HttpMethod.Get && method != HttpMethod.Head && method != HttpMethod.Options) {
+ if (method != HttpMethod.Get && method != HttpMethod.Head && method != HttpMethod.Options)
+ {
return base.SendAsync(request, cancellationToken);
}
- var cacheResult = this.cacheResult;
- if (cacheResult == null && NetCache.RequestCache != null) {
+ var cacheResult = _cacheResult;
+ if (cacheResult == null && NetCache.RequestCache != null)
+ {
cacheResult = NetCache.RequestCache.Save;
}
- if (maxBytesToRead != null && maxBytesToRead.Value < 0) {
+ if (_maxBytesToRead != null && _maxBytesToRead.Value < 0)
+ {
var tcs = new TaskCompletionSource();
tcs.SetCanceled();
return tcs.Task;
@@ -79,96 +112,87 @@ protected override Task SendAsync(HttpRequestMessage reques
var key = UniqueKeyForRequest(request);
var realToken = new CancellationTokenSource();
- var ret = new InflightRequest(() => {
- lock (inflightResponses) inflightResponses.Remove(key);
+ var ret = new InflightRequest(() =>
+ {
+ lock (_inflightResponses)
+ {
+ _inflightResponses.Remove(key);
+ }
+
realToken.Cancel();
});
- lock (inflightResponses) {
- if (inflightResponses.ContainsKey(key)) {
- var val = inflightResponses[key];
+ lock (_inflightResponses)
+ {
+ if (_inflightResponses.ContainsKey(key))
+ {
+ var val = _inflightResponses[key];
val.AddRef();
cancellationToken.Register(val.Cancel);
return val.Response.ToTask(cancellationToken);
}
- inflightResponses[key] = ret;
+ _inflightResponses[key] = ret;
}
cancellationToken.Register(ret.Cancel);
- var queue = this.opQueue ?? NetCache.OperationQueue;
-
- queue.Enqueue(priority, null, realToken.Token, async () => {
- try {
- var resp = await base.SendAsync(request, realToken.Token);
-
- if (maxBytesToRead != null && resp.Content != null && resp.Content.Headers.ContentLength != null) {
- maxBytesToRead -= resp.Content.Headers.ContentLength;
+ var queue = _opQueue ?? NetCache.OperationQueue;
+
+ queue.Enqueue(
+ _priority,
+ null,
+ async () =>
+ {
+ try
+ {
+ var resp = await base.SendAsync(request, realToken.Token).ConfigureAwait(false);
+
+ if (_maxBytesToRead != null && resp.Content != null && resp.Content.Headers.ContentLength != null)
+ {
+ _maxBytesToRead -= resp.Content.Headers.ContentLength;
+ }
+
+ if (cacheResult != null && resp.Content != null)
+ {
+ var ms = new MemoryStream();
+ var stream = await resp.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ await stream.CopyToAsync(ms, 32 * 1024, realToken.Token).ConfigureAwait(false);
+
+ realToken.Token.ThrowIfCancellationRequested();
+
+ var newResp = new HttpResponseMessage();
+ foreach (var kvp in resp.Headers)
+ {
+ newResp.Headers.Add(kvp.Key, kvp.Value);
+ }
+
+ var newContent = new ByteArrayContent(ms.ToArray());
+ foreach (var kvp in resp.Content.Headers)
+ {
+ newContent.Headers.Add(kvp.Key, kvp.Value);
+ }
+
+ newResp.Content = newContent;
+
+ resp = newResp;
+ await cacheResult(request, resp, key, realToken.Token).ConfigureAwait(false);
+ }
+
+ return resp;
}
-
- if (cacheResult != null && resp.Content != null) {
- var ms = new MemoryStream();
- var stream = await resp.Content.ReadAsStreamAsync();
- await stream.CopyToAsync(ms, 32 * 1024, realToken.Token);
-
- realToken.Token.ThrowIfCancellationRequested();
-
- var newResp = new HttpResponseMessage();
- foreach (var kvp in resp.Headers) { newResp.Headers.Add(kvp.Key, kvp.Value); }
-
- var newContent = new ByteArrayContent(ms.ToArray());
- foreach (var kvp in resp.Content.Headers) { newContent.Headers.Add(kvp.Key, kvp.Value); }
- newResp.Content = newContent;
-
- resp = newResp;
- await cacheResult(request, resp, key, realToken.Token);
+ finally
+ {
+ lock (_inflightResponses)
+ {
+ _inflightResponses.Remove(key);
+ }
}
-
- return resp;
- } finally {
- lock(inflightResponses) inflightResponses.Remove(key);
- }
- }).ToObservable().Subscribe(ret.Response);
+ },
+ realToken.Token).ToObservable().Subscribe(ret.Response);
return ret.Response.ToTask(cancellationToken);
}
-
- public override void ResetLimit(long? maxBytesToRead = null)
- {
- this.maxBytesToRead = maxBytesToRead;
- }
-
- public static string UniqueKeyForRequest(HttpRequestMessage request)
- {
- var ret = new[] {
- request.RequestUri.ToString(),
- request.Method.Method,
- request.Headers.Accept.ConcatenateAll(x => x.CharSet + x.MediaType),
- request.Headers.AcceptEncoding.ConcatenateAll(x => x.Value),
- (request.Headers.Referrer ?? new Uri("http://example")).AbsoluteUri,
- request.Headers.UserAgent.ConcatenateAll(x => (x.Product != null ? x.Product.ToString() : x.Comment)),
- }.Aggregate(new StringBuilder(), (acc, x) => { acc.AppendLine(x); return acc; });
-
- if (request.Headers.Authorization != null) {
- ret.AppendLine(request.Headers.Authorization.Parameter + request.Headers.Authorization.Scheme);
- }
-
- return "HttpSchedulerCache_" + ret.ToString().GetHashCode().ToString("x", CultureInfo.InvariantCulture);
- }
- }
-
- internal static class ConcatenateMixin
- {
- public static string ConcatenateAll(this IEnumerable This, Func selector, char separator = '|')
- {
- return This.Aggregate(new StringBuilder(), (acc, x) =>
- {
- acc.Append(selector(x));
- acc.Append(separator);
- return acc;
- }).ToString();
- }
}
}
diff --git a/src/Rebracer.xml b/src/Rebracer.xml
deleted file mode 100644
index db058f8..0000000
--- a/src/Rebracer.xml
+++ /dev/null
@@ -1,231 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- TODO:2
- HACK:2
- UNDONE:2
- UnresolvedMergeConflict:3
-
- true
- true
- false
-
-
-
-
- 1
- 1
- 1
- 1
- 1
- 0
- 1
- 0
- 0
- 2
- 0
- 1
- 1
- 1
- 0
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 0
- 1
- 0
- 0
- 0
- 1
- 1
- 1
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 1
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 1
- 1
-
-
- false
- true
- true
- true
- true
- Implicit (Windows 8.0)|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\libhelp.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\sitetypesWindows.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\domWindows_8.0.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\underscorefilter.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\showPlainComments.js;Implicit (Windows 8.1)|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\libhelp.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\sitetypesWindows.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\domWindows_8.1.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\underscorefilter.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\showPlainComments.js;Implicit (Web)|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\libhelp.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\sitetypesWeb.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\domWeb.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\underscorefilter.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\showPlainComments.js|~/Scripts/_references.js;Dedicated Worker|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\libhelp.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\dedicatedworker.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\underscorefilter.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\showPlainComments.js;Generic|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\libhelp.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\underscorefilter.js|C:\Program Files (x86)\Microsoft Visual Studio 12.0\JavaScript\References\showPlainComments.js;
- true
- true
- true
- false
- true
- true
- false
- false
- true
- true
-
-
- true
- false
- false
- true
- true
- true
- true
- false
- true
- true
- false
- true
- false
- false
- false
- false
- false
- false
- false
- false
- false
- false
- false
- false
- false
- false
- false
- false
- false
- false
- false
- false
- false
- true
- true
- true
-
- true
- false
- true
- false
- true
- false
- true
- false
- 1
- true
- 0
- 5
- 2
- false
- {}[]().,:;+-*/%&|^!=<>?@#\
- true
- 3
- 0
- true
- true
- 0
- 0
- true
- true
- false
- 0
- 0
- 0
- 1
- false
- false
- true
- false
- 60
- false
- false
- true
- true
- 2
- 2
- 2
- false
- false
- true
- true
- false
- false
- true
- false
- false
- false
- false
- false
- false
- false
- false
- false
- false
- false
- true
- false
- true
- true
- false
-
-
- false
- true
- true
- true
- true
- true
- true
- true
- false
- true
- true
- false
- false
- true
- false
- false
- false
-
-
- true
- true
- true
- true
- true
- true
-
-
-
-
\ No newline at end of file
diff --git a/src/analyzers.ruleset b/src/analyzers.ruleset
new file mode 100644
index 0000000..c1436ad
--- /dev/null
+++ b/src/analyzers.ruleset
@@ -0,0 +1,280 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/analyzers.tests.ruleset b/src/analyzers.tests.ruleset
new file mode 100644
index 0000000..191cfed
--- /dev/null
+++ b/src/analyzers.tests.ruleset
@@ -0,0 +1,284 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/global.json b/src/global.json
new file mode 100644
index 0000000..73fa45c
--- /dev/null
+++ b/src/global.json
@@ -0,0 +1,5 @@
+{
+ "msbuild-sdks": {
+ "MSBuild.Sdk.Extras": "1.6.65"
+ }
+}
diff --git a/src/stylecop.json b/src/stylecop.json
new file mode 100644
index 0000000..66c88ad
--- /dev/null
+++ b/src/stylecop.json
@@ -0,0 +1,41 @@
+{
+ "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
+ "settings": {
+ "indentation": {
+ "useTabs": false,
+ "indentationSize": 4
+ },
+ "documentationRules": {
+ "documentExposedElements": true,
+ "documentInternalElements": false,
+ "documentPrivateElements": false,
+ "documentInterfaces": true,
+ "documentPrivateFields": false,
+ "documentationCulture": "en-US",
+ "companyName": ".NET Foundation and Contributors",
+ "copyrightText": "Copyright (c) 2019 {companyName}. All rights reserved.\nLicensed to the .NET Foundation under one or more agreements.\nThe .NET Foundation licenses this file to you under the {licenseName} license.\nSee the {licenseFile} file in the project root for full license information.",
+ "variables": {
+ "licenseName": "MIT",
+ "licenseFile": "LICENSE"
+ },
+ "xmlHeader": false
+ },
+ "layoutRules": {
+ "newlineAtEndOfFile": "allow",
+ "allowConsecutiveUsings": true
+ },
+ "maintainabilityRules": {
+ "topLevelTypes": [
+ "class",
+ "interface",
+ "struct",
+ "enum",
+ "delegate"
+ ]
+ },
+ "orderingRules": {
+ "usingDirectivesPlacement": "outsideNamespace",
+ "systemUsingDirectivesFirst": true
+ },
+ }
+}
diff --git a/version.json b/version.json
new file mode 100644
index 0000000..625ed82
--- /dev/null
+++ b/version.json
@@ -0,0 +1,17 @@
+{
+ "version": "2.0",
+ "publicReleaseRefSpec": [
+ "^refs/heads/master$", // we release out of master
+ "^refs/heads/develop$", // we release out of develop
+ "^refs/heads/rel/\\d+\\.\\d+\\.\\d+" // we also release branches starting with rel/N.N.N
+ ],
+ "nugetPackageVersion":{
+ "semVer": 2
+ },
+ "cloudBuild": {
+ "setVersionVariables": true,
+ "buildNumber": {
+ "enabled": false
+ }
+ }
+}