diff --git a/.gitignore b/.gitignore
index 43e1adf..7a53e95 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,26 +4,50 @@
# User-specific files
*.suo
*.user
+*.userosscache
*.sln.docstates
-# Build results
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+# Build results
[Dd]ebug/
+[Dd]ebugPublic/
[Rr]elease/
+[Rr]eleases/
x64/
-build/
+x86/
+bld/
[Bb]in/
[Oo]bj/
+[Ll]og/
+#[Aa]rtifacts/
-# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
-!packages/*/build/
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+artifacts/
+
*_i.c
*_p.c
+*_i.h
*.ilk
*.meta
*.obj
@@ -43,21 +67,31 @@ build/
*.vssscc
.builds
*.pidb
-*.log
+*.svclog
*.scc
+# Chutzpah Test files
+_Chutzpah*
+
# Visual C++ cache files
ipch/
*.aps
*.ncb
+*.opendb
*.opensdf
*.sdf
*.cachefile
+*.VC.db
+*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
# Guidance Automation Toolkit
*.gpState
@@ -65,6 +99,10 @@ ipch/
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
# TeamCity is a build add-in
_TeamCity*
@@ -73,8 +111,16 @@ _TeamCity*
*.dotCover
# NCrunch
-*.ncrunch*
+_NCrunch_*
.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
# Installshield output folder
[Ee]xpress/
@@ -93,67 +139,129 @@ DocProject/Help/html
publish/
# Publish Web Output
-*.Publish.xml
-
-# NuGet Packages Directory
-## TODO: If you have NuGet Package Restore enabled, uncomment the next line
-packages/
-
-# Windows Azure Build Output
-csx
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
*.build.csdef
-# Windows Store app package directory
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
# Others
-sql/
-*.Cache
ClientBin/
-[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
-*.[Pp]ublish.xml
+*.dbproj.schemaview
*.pfx
*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
# RIA/Silverlight projects
Generated_Code/
-# Backup & report files from converting an old project file to a newer
-# Visual Studio version. Backup files are not needed, because we have git ;-)
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
-App_Data/*.mdf
-App_Data/*.ldf
-
-
-#LightSwitch generated files
-GeneratedArtifacts/
-_Pvt_Extensions/
-ModelManifest.xml
-
-# =========================
-# Windows detritus
-# =========================
-
-# Windows image file caches
-Thumbs.db
-ehthumbs.db
-
-# Folder config file
-Desktop.ini
-
-# Recycle Bin used on file shares
-$RECYCLE.BIN/
-
-# Mac desktop service store files
-.DS_Store
-
-# Nuget packages
-*.nupkg
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CAKE
+**/tools/Addins/
+**/tools/Cake/
+**/tools/GitVersion.CommandLine
+**/tools/nuget.exe
+**/tools/NUnit.ConsoleRunner
+**/tools/run-ps.cmd
+**/tools/publish-nugetpackages.ps1
+**/tools/packages.config.md5sum
+
+# Xamarin
+/source/Components
+/tools/xunit.runner.console/tools
diff --git a/.nuget/NuGet.Config b/.nuget/NuGet.Config
new file mode 100644
index 0000000..67f8ea0
--- /dev/null
+++ b/.nuget/NuGet.Config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.nuget/packages.config b/.nuget/packages.config
deleted file mode 100644
index 6bc0ed0..0000000
--- a/.nuget/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/Nancy.CustomErrors.Example/Program.cs b/Nancy.CustomErrors.Example/Program.cs
deleted file mode 100755
index 740c5e2..0000000
--- a/Nancy.CustomErrors.Example/Program.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Nancy.Hosting.Self;
-
-namespace Nancy.CustomErrors.Example
-{
- class Program
- {
- static void Main(string[] args)
- {
- using (var host = new NancyHost(new Uri("http://localhost:1234")))
- {
- host.Start();
- Console.ReadKey();
- }
- }
- }
-
- public class TestBootstrapper : DefaultNancyBootstrapper
- {
- protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
- {
- base.ApplicationStartup(container, pipelines);
-
- CustomErrors.Enable(pipelines, new ErrorConfiguration());
- }
- }
-
- public class TestModule : NancyModule
- {
- public TestModule()
- : base("/")
- {
- Get["/test"] = _ =>
- {
- var response = Response.AsText("test", "application/json");
- response.StatusCode = HttpStatusCode.InternalServerError;
- return response;
- };
-
- Get["/err"] = _ =>
- {
- throw new Exception("asdadsfdaf");
- };
- }
- }
-
- public class ErrorConfiguration : CustomErrorsConfiguration
- {
- public ErrorConfiguration()
- {
- // Map error status codes to custom view names
- ErrorViews[HttpStatusCode.NotFound] = "error";
- ErrorViews[HttpStatusCode.InternalServerError] = "error";
- ErrorViews[HttpStatusCode.Forbidden] = "error";
- }
- public override ErrorResponse HandleError(NancyContext context, Exception ex, ISerializer serializer)
- {
- var error = new Error
- {
- FullException = ex.ToString(),
- Message = ex.Message
- };
-
- return new ErrorResponse(error, serializer).WithStatusCode(HttpStatusCode.InternalServerError) as ErrorResponse;
- }
- }
-}
diff --git a/Nancy.CustomErrors.Example/Views/error.html b/Nancy.CustomErrors.Example/Views/error.html
deleted file mode 100755
index b4fe785..0000000
--- a/Nancy.CustomErrors.Example/Views/error.html
+++ /dev/null
@@ -1 +0,0 @@
-ERROR!
\ No newline at end of file
diff --git a/Nancy.CustomErrors.Example/packages.config b/Nancy.CustomErrors.Example/packages.config
deleted file mode 100755
index 152fbff..0000000
--- a/Nancy.CustomErrors.Example/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/Nancy.CustomErrors.Tests/CustomErrorsFixture.cs b/Nancy.CustomErrors.Tests/CustomErrorsFixture.cs
deleted file mode 100644
index c80e24e..0000000
--- a/Nancy.CustomErrors.Tests/CustomErrorsFixture.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System;
-using System.Net;
-using Nancy.Bootstrapper;
-using Nancy.Testing;
-using NSubstitute;
-using Xunit;
-
-namespace Nancy.CustomErrors.Tests
-{
- public class CustomErrorsFixture
- {
- [Fact]
- public void Should_throw_with_null_pipelines_passed_to_enable()
- {
- Assert.Throws(() => CustomErrors.Enable(null, new CustomErrorsConfiguration()));
- }
-
- [Fact]
- public void Should_throw_with_null_configuration_passed_to_enable()
- {
- Assert.Throws(() => CustomErrors.Enable(Substitute.For(), null));
- }
-
- [Fact]
- public void Should_add_error_hook_when_enabled()
- {
- var pipelines = Substitute.For();
- pipelines.OnError.Returns(Substitute.For());
-
- CustomErrors.Enable(pipelines, Substitute.For());
-
- pipelines.OnError.Received(1).AddItemToEndOfPipeline(Arg.Any>());
- }
- }
-}
diff --git a/Nancy.CustomErrors.Tests/ErrorStatusCodeHandlerFixture.cs b/Nancy.CustomErrors.Tests/ErrorStatusCodeHandlerFixture.cs
deleted file mode 100644
index edc1208..0000000
--- a/Nancy.CustomErrors.Tests/ErrorStatusCodeHandlerFixture.cs
+++ /dev/null
@@ -1,152 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Nancy.Testing;
-using Xunit;
-
-namespace Nancy.CustomErrors.Tests
-{
- public class ErrorStatusCodeHandlerFixture
- {
- private readonly CustomErrorsConfiguration configuration;
- private readonly Browser browser;
-
- public ErrorStatusCodeHandlerFixture()
- {
- configuration = new CustomErrorsConfiguration();
-
- browser = new Browser(new ConfigurableBootstrapper(with =>
- {
- with.ApplicationStartup((container, pipelines) => CustomErrors.Enable(pipelines, configuration));
- with.Module();
- with.StatusCodeHandler();
- }));
- }
-
-
- [Fact]
- public void Should_return_custom_error_response_for_route_not_found()
- {
- var response = browser.Get("/nuffin", with => with.Header("Accept", "application/json"));
-
- Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
- Assert.Equal("The requested resource could not be found.", response.Body.DeserializeJson().Message);
- }
-
- [Fact]
- public void Should_return_json_for_application_json_accept_header()
- {
- var response = browser.Get("/error", with => with.Header("Accept", "application/json"));
-
- Assert.NotNull(response.Body.DeserializeJson());
- }
-
- [Fact]
- public void Should_return_json_for_text_json_accept_header()
- {
- var response = browser.Get("/error", with => with.Header("Accept", "text/json"));
-
- Assert.NotNull(response.Body.DeserializeJson());
- }
-
- [Fact]
- public void Should_return_html_for_text_html_accept_header()
- {
- var response = browser.Get("/error", with => with.Header("Accept", "text/html"));
-
- response.Body["title"].ShouldExistOnce().And.ShouldContain(configuration.ErrorTitle);
- }
-
- [Fact]
- public void Should_return_html_no_accept_header()
- {
- var response = browser.Get("/error");
-
- response.Body["title"].ShouldExistOnce().And.ShouldContain(configuration.ErrorTitle);
- }
-
- [Fact]
- public void Should_return_custom_error_response_for_uncaught_exception()
- {
- var response = browser.Get("/error", with => with.Header("Accept", "application/json"));
-
- Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
- Assert.Equal("ERROR MESSAGE HERE", response.Body.DeserializeJson().Message);
- }
-
- [Fact]
- public void Should_return_custom_error_response_for_forbidden()
- {
- var response = browser.Get("forbidden", with => with.Header("Accept", "application/json"));
-
- Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
- Assert.NotNull(response.Body.DeserializeJson());
- }
-
- [Fact]
- public void Should_return_custom_error_response_for_unauthorised()
- {
- var response = browser.Get("unauthorised", with => with.Header("Accept", "application/json"));
-
- Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
- Assert.NotNull(response.Body.DeserializeJson());
- }
-
- [Fact]
- public void Should_render_custom_html_for_uncaught_exception()
- {
- var response = browser.Get("error");
-
- response.Body["title"].ShouldExistOnce().And.ShouldContain(configuration.ErrorTitle);
- response.Body["h1"].ShouldExistOnce().And.ShouldContain("ERROR MESSAGE HERE");
- }
-
- [Fact]
- public void Should_suppress_full_stack_trace_by_default()
- {
- var response = browser.Get("/err", with => with.Header("Accept", "application/json"));
-
- Assert.Null(response.Body.DeserializeJson().FullException);
- }
-
- [Fact]
- public void Should_expose_full_stack_trace_in_debug_mode()
- {
- CustomErrors.Configuration.Debug = true;
-
- var response = browser.Get("/error", with => with.Header("Accept", "application/json"));
-
- Assert.NotNull(response.Body.DeserializeJson().FullException);
-
- CustomErrors.Configuration.Debug = false;
- }
-
- [Fact]
- public void Should_retain_headers_already_set()
- {
- var response = browser.Get("/headers", with => with.Header("Accept", "application/json"));
-
- Assert.NotNull(response.Headers.Where(h => h.Key == "CustomHeader"));
- }
- }
-
-
- public class TestModule : NancyModule
- {
- public TestModule()
- {
- Get["error"] = _ =>
- {
- throw new Exception("ERROR MESSAGE HERE");
- };
-
- Get["forbidden"] = _ => HttpStatusCode.Forbidden;
- Get["unauthorised"] = _ => HttpStatusCode.Unauthorized;
- Get["headers"] =
- _ =>
- new Response().WithStatusCode(HttpStatusCode.InternalServerError)
- .WithHeader("CustomHeader", "CustomHeaderValue");
- }
- }
-}
diff --git a/Nancy.CustomErrors.Tests/Nancy.CustomErrors.Tests.csproj b/Nancy.CustomErrors.Tests/Nancy.CustomErrors.Tests.csproj
deleted file mode 100644
index 8957f70..0000000
--- a/Nancy.CustomErrors.Tests/Nancy.CustomErrors.Tests.csproj
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
-
-
- Debug
- AnyCPU
- {F1930050-9A83-42BB-9E14-1D5D7C6F255B}
- Library
- Properties
- Nancy.CustomErrors.Tests
- Nancy.CustomErrors.Tests
- v4.0
- 512
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
- ..\packages\CsQuery.1.3.4\lib\net40\CsQuery.dll
-
-
- ..\packages\Nancy.0.23.0\lib\net40\Nancy.dll
-
-
- ..\packages\Nancy.Testing.0.23.0\lib\net40\Nancy.Testing.dll
-
-
- ..\packages\NSubstitute.1.7.2.0\lib\NET40\NSubstitute.dll
-
-
-
-
-
-
-
-
-
- ..\packages\xunit.1.9.2\lib\net20\xunit.dll
-
-
-
-
-
-
-
-
-
-
-
-
- {cd7a7211-6563-499b-913d-8e5af649bfe7}
- Nancy.CustomErrors
-
-
-
-
- PreserveNewest
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Nancy.CustomErrors.Tests/packages.config b/Nancy.CustomErrors.Tests/packages.config
deleted file mode 100644
index 5aa926e..0000000
--- a/Nancy.CustomErrors.Tests/packages.config
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Nancy.CustomErrors.sln b/Nancy.CustomErrors.sln
index 1d8d98f..87163f5 100644
--- a/Nancy.CustomErrors.sln
+++ b/Nancy.CustomErrors.sln
@@ -1,9 +1,9 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.31101.0
+# Visual Studio 15
+VisualStudioVersion = 15.0.26430.6
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nancy.CustomErrors", "Nancy.CustomErrors\Nancy.CustomErrors.csproj", "{CD7A7211-6563-499B-913D-8E5AF649BFE7}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nancy.CustomErrors", "src\Nancy.CustomErrors\Nancy.CustomErrors.csproj", "{CD7A7211-6563-499B-913D-8E5AF649BFE7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{56730B51-095D-4010-B942-DCB2696540C0}"
ProjectSection(SolutionItems) = preProject
@@ -13,16 +13,23 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
version.json = version.json
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nancy.CustomErrors.Tests", "Nancy.CustomErrors.Tests\Nancy.CustomErrors.Tests.csproj", "{F1930050-9A83-42BB-9E14-1D5D7C6F255B}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nancy.CustomErrors.Tests", "tests\Nancy.CustomErrors.Tests\Nancy.CustomErrors.Tests.csproj", "{F1930050-9A83-42BB-9E14-1D5D7C6F255B}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nancy.CustomErrors.Example", "Nancy.CustomErrors.Example\Nancy.CustomErrors.Example.csproj", "{5A8E7514-E653-4C00-8623-1E71D7DCE6C5}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nancy.CustomErrors.Example", "tests\Nancy.CustomErrors.Example\Nancy.CustomErrors.Example.csproj", "{5A8E7514-E653-4C00-8623-1E71D7DCE6C5}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1831399C-85E4-4E38-893C-F85DB092CB04}"
- ProjectSection(SolutionItems) = preProject
- .nuget\packages.config = .nuget\packages.config
- EndProjectSection
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nancy.CustomErrors.NetStandard1.6", "src\Nancy.CustomErrors.NetStandard1.6\Nancy.CustomErrors.NetStandard1.6.csproj", "{BBFAEB4A-212F-4F00-AAE7-6723231C6969}"
+EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Nancy.CustomErrors.Shared", "src\Nancy.CustomErrors.Shared\Nancy.CustomErrors.Shared.shproj", "{0B0C2E66-9FD4-4475-AB31-81AB2F39F4DA}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "source", "source", "{ED70835A-FD7E-43C7-803D-84CD326DA186}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{9CDF45E1-7B40-4BA2-A537-1407CA214AD0}"
EndProject
Global
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ src\Nancy.CustomErrors.Shared\Nancy.CustomErrors.Shared.projitems*{0b0c2e66-9fd4-4475-ab31-81ab2f39f4da}*SharedItemsImports = 13
+ src\Nancy.CustomErrors.Shared\Nancy.CustomErrors.Shared.projitems*{cd7a7211-6563-499b-913d-8e5af649bfe7}*SharedItemsImports = 4
+ EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
@@ -40,8 +47,19 @@ Global
{5A8E7514-E653-4C00-8623-1E71D7DCE6C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5A8E7514-E653-4C00-8623-1E71D7DCE6C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5A8E7514-E653-4C00-8623-1E71D7DCE6C5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BBFAEB4A-212F-4F00-AAE7-6723231C6969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BBFAEB4A-212F-4F00-AAE7-6723231C6969}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BBFAEB4A-212F-4F00-AAE7-6723231C6969}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BBFAEB4A-212F-4F00-AAE7-6723231C6969}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {CD7A7211-6563-499B-913D-8E5AF649BFE7} = {ED70835A-FD7E-43C7-803D-84CD326DA186}
+ {F1930050-9A83-42BB-9E14-1D5D7C6F255B} = {9CDF45E1-7B40-4BA2-A537-1407CA214AD0}
+ {5A8E7514-E653-4C00-8623-1E71D7DCE6C5} = {9CDF45E1-7B40-4BA2-A537-1407CA214AD0}
+ {BBFAEB4A-212F-4F00-AAE7-6723231C6969} = {ED70835A-FD7E-43C7-803D-84CD326DA186}
+ {0B0C2E66-9FD4-4475-AB31-81AB2F39F4DA} = {ED70835A-FD7E-43C7-803D-84CD326DA186}
+ EndGlobalSection
EndGlobal
diff --git a/Nancy.CustomErrors/CustomErrors.cs b/Nancy.CustomErrors/CustomErrors.cs
deleted file mode 100644
index 5a0d446..0000000
--- a/Nancy.CustomErrors/CustomErrors.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using System;
-using Nancy.Bootstrapper;
-using Nancy.Responses;
-
-namespace Nancy.CustomErrors
-{
- public class CustomErrors
- {
- private static CustomErrorsConfiguration _configuration;
- public static CustomErrorsConfiguration Configuration
- {
- get
- {
- return _configuration;
- }
- }
-
- public static void Enable(IPipelines pipelines, CustomErrorsConfiguration configuration)
- {
- Enable(pipelines, configuration, new DefaultJsonSerializer());
- }
-
- public static void Enable(IPipelines pipelines, CustomErrorsConfiguration configuration, ISerializer serializer)
- {
- if (pipelines == null)
- {
- throw new ArgumentNullException("pipelines");
- }
-
- if (configuration == null)
- {
- throw new ArgumentNullException("configuration");
- }
-
- _configuration = configuration;
-
- pipelines.OnError.AddItemToEndOfPipeline(GetErrorHandler(configuration, serializer));
- }
-
- private static Func GetErrorHandler(CustomErrorsConfiguration configuration, ISerializer serializer)
- {
- return (context, ex) => configuration.HandleError(context, ex, serializer);
- }
- }
-}
\ No newline at end of file
diff --git a/Nancy.CustomErrors/CustomErrorsConfiguration.cs b/Nancy.CustomErrors/CustomErrorsConfiguration.cs
deleted file mode 100644
index e101bec..0000000
--- a/Nancy.CustomErrors/CustomErrorsConfiguration.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Nancy.CustomErrors
-{
- public class CustomErrorsConfiguration
- {
- public string NotFoundTitle = "404 Not Found";
- public string NotFoundSummary = "The requested resource could not be found.";
- public string ForbiddenTitle = "Forbidden";
- public string ForbiddenSummary = "You do not have permission to do that.";
- public string UnauthorizedTitle = "Unauthorized";
- public string UnauthorizedSummary = "You do not have permission to do that.";
- public string ErrorTitle = "Error";
- public string ErrorSummary = "An unexpected error occurred.";
-
- public bool AlwaysReturnJson = false;
-
- ///
- /// If set to true, then we will emit full stack traces in our ErrorResponse
- ///
- public bool Debug = false;
-
- ///
- /// Converts a thrown exception to the appropriate ErrorResponse. Override this method if you need
- /// to handle custom exception types, or implement your own error handling logic. The default
- /// implementation converts all thrown exceptions to a regular ErrorResponse with an HttpStatusCode
- /// of 500
- ///
- ///
- ///
- ///
- ///
- public virtual ErrorResponse HandleError(NancyContext context, Exception ex, ISerializer serializer)
- {
- var error = new Error
- {
- FullException = ex.ToString(),
- Message = ex.Message
- };
-
- return new ErrorResponse(error, serializer).WithStatusCode(HttpStatusCode.InternalServerError) as ErrorResponse;
- }
-
- ///
- /// Maps different HttpStatusCodes to the appropriate views.
- ///
- public IDictionary ErrorViews = new Dictionary
- {
- { HttpStatusCode.NotFound, "Error" },
- { HttpStatusCode.InternalServerError, "Error" },
- { HttpStatusCode.Forbidden, "Error" }
- };
- }
-}
diff --git a/Nancy.CustomErrors/Error.cs b/Nancy.CustomErrors/Error.cs
deleted file mode 100644
index 2948a12..0000000
--- a/Nancy.CustomErrors/Error.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-
-namespace Nancy.CustomErrors
-{
- public class Error
- {
- public string Message { get; set; }
- public string FullException { get; set; }
- }
-}
\ No newline at end of file
diff --git a/Nancy.CustomErrors/ErrorResponse.cs b/Nancy.CustomErrors/ErrorResponse.cs
deleted file mode 100644
index 1ce1315..0000000
--- a/Nancy.CustomErrors/ErrorResponse.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using Nancy.Responses;
-
-namespace Nancy.CustomErrors
-{
- public class ErrorResponse : JsonResponse
- {
- private readonly Error _error;
- public string ErrorMessage { get { return _error.Message; } }
- public string FullException { get { return _error.FullException; } }
- public ErrorResponse(Error error) : this(error, new DefaultJsonSerializer()) { }
- public ErrorResponse(Error error, ISerializer serializer) : base(error, serializer)
- {
- if (!CustomErrors.Configuration.Debug)
- {
- error.FullException = null;
- }
-
- _error = error;
- }
- }
-}
diff --git a/Nancy.CustomErrors/ErrorStatusCodeHandler.cs b/Nancy.CustomErrors/ErrorStatusCodeHandler.cs
deleted file mode 100644
index a14ee0f..0000000
--- a/Nancy.CustomErrors/ErrorStatusCodeHandler.cs
+++ /dev/null
@@ -1,172 +0,0 @@
-using System;
-using System.IO;
-using System.Linq;
-using System.Net;
-using Nancy.ErrorHandling;
-using Nancy.Responses;
-using Nancy.Responses.Negotiation;
-using Nancy.ViewEngines;
-
-namespace Nancy.CustomErrors
-{
- public class ErrorStatusCodeHandler : DefaultViewRenderer, IStatusCodeHandler
- {
- private readonly ISerializer _serializer;
-
- public ErrorStatusCodeHandler(IViewFactory viewFactory)
- : this(viewFactory, new DefaultJsonSerializer())
- {
- }
-
- public ErrorStatusCodeHandler(IViewFactory viewFactory, ISerializer serializer)
- : base(viewFactory)
- {
- _serializer = serializer;
- }
-
- public bool HandlesStatusCode(HttpStatusCode statusCode, NancyContext context)
- {
- return statusCode == HttpStatusCode.NotFound
- || statusCode == HttpStatusCode.InternalServerError
- || statusCode == HttpStatusCode.Forbidden
- || statusCode == HttpStatusCode.Unauthorized;
- }
-
- public void Handle(HttpStatusCode statusCode, NancyContext context)
- {
- var headers = context.Response.Headers.Select(h => Tuple.Create(h.Key, h.Value)).ToArray();
-
- if (!ShouldRenderFriendlyErrorPage(context))
- {
- // Assume a valid error response was built earlier in the request lifecycle
- // Nothing more for us to do here, so just bail out.
- if (context.Response is ErrorResponse)
- {
- return;
- }
-
- var err = new Error
- {
- Message = CustomErrors.Configuration.ErrorSummary
- };
-
- if (context.Response is NotFoundResponse)
- {
- // Normally we return 404's ourselves so we have an ErrorResponse.
- // But if no route is matched, Nancy will set a NotFound response itself.
- // When this happens we still want to return our nice JSON response.
- err.Message = CustomErrors.Configuration.NotFoundSummary;
- }
- else
- {
- switch (statusCode)
- {
- case HttpStatusCode.Forbidden :
- case HttpStatusCode.Unauthorized :
- err.Message = CustomErrors.Configuration.UnauthorizedSummary;
- break;
- case HttpStatusCode.NotFound :
- err.Message = CustomErrors.Configuration.NotFoundSummary;
- context.Response = new ErrorResponse(new Error
- {
- Message = CustomErrors.Configuration.NotFoundSummary
- });
- break;
- }
- }
-
- context.Response = new ErrorResponse(err, _serializer).WithHeaders(headers).WithStatusCode(statusCode);
-
- return;
- }
-
- var error = context.Response as ErrorResponse;
-
- var model = new ErrorViewModel
- {
- Details = error == null ? "" : error.FullException
- };
-
- switch (statusCode)
- {
- case HttpStatusCode.Forbidden:
- model.Title = CustomErrors.Configuration.ForbiddenTitle;
- model.Summary = CustomErrors.Configuration.ForbiddenSummary;
-
- break;
-
- case HttpStatusCode.Unauthorized:
- model.Title = CustomErrors.Configuration.UnauthorizedTitle;
- model.Summary = error == null ? CustomErrors.Configuration.UnauthorizedSummary : error.ErrorMessage;
-
- break;
-
- case HttpStatusCode.NotFound:
- model.Title = CustomErrors.Configuration.NotFoundTitle;
- model.Summary = CustomErrors.Configuration.NotFoundSummary;
-
- break;
- case HttpStatusCode.InternalServerError:
- model.Title = CustomErrors.Configuration.ErrorTitle;
- model.Summary = error == null ? CustomErrors.Configuration.ErrorSummary : error.ErrorMessage;
-
- break;
- }
-
- try
- {
- context.Response =
- RenderView(context, CustomErrors.Configuration.ErrorViews[statusCode], model)
- .WithStatusCode(statusCode)
- .WithHeaders(headers);
- }
- catch(Exception e)
- {
- context.Response = new Response
- {
- StatusCode = HttpStatusCode.InternalServerError,
- ContentType = "text/plain",
- Contents = stream =>
- {
- var writer = new StreamWriter(stream);
- writer.AutoFlush = true;
- writer.Write(string.Format("Could not locate your error view! Details: {0}", e.Message));
- }
- };
- }
- }
-
- private static bool ShouldRenderFriendlyErrorPage(NancyContext context)
- {
- if (CustomErrors.Configuration.AlwaysReturnJson)
- {
- return false;
- }
-
- var ranges =
- context.Request.Headers.Accept.OrderByDescending(o => o.Item2)
- .Select(o => MediaRange.FromString(o.Item1))
- .ToList();
-
- foreach (var range in ranges)
- {
- if (range.Matches("application/json"))
- {
- return false;
- }
-
- if (range.Matches("text/json"))
- {
- return false;
- }
-
- if (range.Matches("text/html"))
- {
- return true;
- }
- }
-
- return true;
- }
- }
-}
\ No newline at end of file
diff --git a/Nancy.CustomErrors/ErrorViewModel.cs b/Nancy.CustomErrors/ErrorViewModel.cs
deleted file mode 100644
index 3895ced..0000000
--- a/Nancy.CustomErrors/ErrorViewModel.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Nancy.CustomErrors
-{
- public class ErrorViewModel
- {
- public string Title { get; set; }
- public string Summary { get; set; }
- public string Details { get; set; }
- }
-}
diff --git a/Nancy.CustomErrors/Nancy.CustomErrors.nuspec b/Nancy.CustomErrors/Nancy.CustomErrors.nuspec
deleted file mode 100644
index 1adf745..0000000
--- a/Nancy.CustomErrors/Nancy.CustomErrors.nuspec
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- $id$
- $version$
- $title$
- $author$
- $author$
- https://github.com/bernos/Nancy.CustomErrors
- Adds exception handling for cases when custom error views cannot be found
- false
- $description$
- Copyright 2014
- Nancyfx
-
-
\ No newline at end of file
diff --git a/Nancy.CustomErrors/ResponseFormatterExtensions.cs b/Nancy.CustomErrors/ResponseFormatterExtensions.cs
deleted file mode 100644
index c10a4c8..0000000
--- a/Nancy.CustomErrors/ResponseFormatterExtensions.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Linq;
-
-namespace Nancy.CustomErrors
-{
- public static class ResponseFormatterExtensions
- {
- public static Response AsError(this IResponseFormatter formatter, string message,
- HttpStatusCode statusCode = HttpStatusCode.InternalServerError)
- {
- var serializer = formatter.Serializers.FirstOrDefault(s => s.CanSerialize("application/json"));
-
- return new ErrorResponse(new Error {Message = message}, serializer).WithStatusCode(statusCode);
- }
- }
-}
\ No newline at end of file
diff --git a/Nancy.CustomErrors/packages.config b/Nancy.CustomErrors/packages.config
deleted file mode 100644
index 722d3f8..0000000
--- a/Nancy.CustomErrors/packages.config
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/build.cake b/build.cake
new file mode 100644
index 0000000..adf0adb
--- /dev/null
+++ b/build.cake
@@ -0,0 +1,360 @@
+///////////////////////////////////////////////////////////////////////////////
+// Directives
+///////////////////////////////////////////////////////////////////////////////
+
+#l "tools/versionUtils.cake"
+#l "tools/settingsUtils.cake"
+#tool "nuget:?package=NUnit.ConsoleRunner"
+#tool "nuget:?package=xunit.runner.console"
+
+///////////////////////////////////////////////////////////////////////////////
+// ARGUMENTS
+///////////////////////////////////////////////////////////////////////////////
+
+var settings = SettingsUtils.LoadSettings(Context);
+var versionInfo = VersionUtils.LoadVersion(Context, settings);
+
+///////////////////////////////////////////////////////////////////////////////
+// GLOBAL VARIABLES
+///////////////////////////////////////////////////////////////////////////////
+
+var solutions = GetFiles(settings.Build.SolutionFilePath);
+var solutionPaths = solutions.Select(solution => solution.GetDirectory());
+
+///////////////////////////////////////////////////////////////////////////////
+// SETUP / TEARDOWN
+///////////////////////////////////////////////////////////////////////////////
+
+Setup((c) =>
+{
+ // Executed BEFORE the first task.
+ settings.Display(c);
+ versionInfo.Display(c);
+});
+
+Teardown((c) =>
+{
+ // Executed AFTER the last task.
+ Information("Finished running tasks.");
+});
+
+///////////////////////////////////////////////////////////////////////////////
+// TASK DEFINITIONS
+///////////////////////////////////////////////////////////////////////////////
+
+Task("CleanAll")
+ .Description("Cleans all directories that are used during the build process.")
+ .Does(() =>
+{
+ // Clean solution directories.
+ foreach(var path in solutionPaths)
+ {
+ Information("Cleaning {0}", path);
+ CleanDirectories(path + "/**/bin");
+ CleanDirectories(path + "/**/obj");
+ CleanDirectories(path + "/packages/**/*");
+ CleanDirectories(path + "/artifacts/**/*");
+ CleanDirectories(path + "/packages");
+ CleanDirectories(path + "/artifacts");
+ }
+
+ var pathTest = MakeAbsolute(Directory(settings.Test.SourcePath)).FullPath;
+ Information("Cleaning {0}", pathTest);
+ try { CleanDirectories(pathTest + "/**/bin"); } catch {}
+ try { CleanDirectories(pathTest + "/**/obj"); } catch {}
+});
+
+Task("Clean")
+ .Description("Cleans all directories that are used during the build process.")
+ .WithCriteria(settings.ExecuteBuild)
+ .Does(() =>
+{
+ // Clean solution directories.
+ foreach(var path in solutionPaths)
+ {
+ Information("Cleaning {0}", path);
+ try { CleanDirectories(path + "/**/bin/" + settings.Configuration); } catch {}
+ try { CleanDirectories(path + "/**/obj/" + settings.Configuration); } catch {}
+ }
+
+ var pathTest = MakeAbsolute(Directory(settings.Test.SourcePath)).FullPath;
+ Information("Cleaning {0}", pathTest);
+ try { CleanDirectories(pathTest + "/**/bin/" + settings.Configuration); } catch {}
+ try { CleanDirectories(pathTest + "/**/obj/" + settings.Configuration); } catch {}
+
+});
+
+Task("CleanPackages")
+ .Description("Cleans all packages that are used during the build process.")
+ .Does(() =>
+{
+ // Clean solution directories.
+ foreach(var path in solutionPaths)
+ {
+ Information("Cleaning {0}", path);
+ CleanDirectories(path + "/packages/**/*");
+ CleanDirectories(path + "/packages");
+ }
+});
+
+Task("Restore")
+ .Description("Restores all the NuGet packages that are used by the specified solution.")
+ .WithCriteria(settings.ExecuteBuild)
+ .Does(() =>
+{
+ // Restore all NuGet packages.
+ foreach(var solution in solutions)
+ {
+ Information("Restoring {0}...", solution);
+ NuGetRestore(solution, new NuGetRestoreSettings { ConfigFile = settings.NuGet.NuGetConfig });
+ }
+});
+
+Task("Build")
+ .Description("Builds all the different parts of the project.")
+ .WithCriteria(settings.ExecuteBuild)
+ .IsDependentOn("Clean")
+ .IsDependentOn("Restore")
+ .IsDependentOn("UpdateVersion")
+ .Does(() =>
+{
+ if (settings.Version.AutoIncrementVersion)
+ {
+ RunTarget("IncrementVersion");
+ }
+
+ // Build all solutions.
+ foreach(var solution in solutions)
+ {
+ Information("Building {0}", solution);
+ try {
+ MSBuild(solution, s =>
+ s.SetPlatformTarget(PlatformTarget.MSIL)
+ .SetMaxCpuCount(settings.Build.MaxCpuCount)
+ .WithProperty("TreatWarningsAsErrors",settings.Build.TreatWarningsAsErrors.ToString())
+ .WithTarget("Build")
+ .SetConfiguration(settings.Configuration));
+ }
+ catch (Exception ex)
+ {
+ Error("Files to build project: " + solution + ". Error: " + ex.Message);
+ }
+ }
+});
+
+Task("UnitTest")
+ .Description("Run unit tests for the solution.")
+ .WithCriteria(settings.ExecuteUnitTest)
+ .IsDependentOn("Build")
+ .Does(() =>
+{
+ // Run all unit tests we can find.
+
+ var assemplyFilePath = string.Format("{0}/**/bin/{1}/{2}", settings.Test.SourcePath, settings.Configuration, settings.Test.AssemblyFileSpec);
+
+ Information("Unit Test Files: {0}", assemplyFilePath);
+
+ var unitTestAssemblies = GetFiles(assemplyFilePath);
+
+ foreach(var uta in unitTestAssemblies)
+ {
+ Information("Executing Tests for {0}", uta);
+
+ switch (settings.Test.Framework)
+ {
+ case TestFrameworkTypes.NUnit2:
+ NUnit(uta.ToString(), new NUnitSettings { });
+ break;
+ case TestFrameworkTypes.NUnit3:
+ NUnit3(uta.ToString(), new NUnit3Settings { Configuration=settings.Configuration });
+ break;
+ case TestFrameworkTypes.XUnit:
+ XUnit(uta.ToString(), new XUnitSettings { OutputDirectory = settings.Test.ResultsPath });
+ break;
+ case TestFrameworkTypes.XUnit2:
+ XUnit2(uta.ToString(), new XUnit2Settings { OutputDirectory = settings.Test.ResultsPath, XmlReportV1 = true });
+ break;
+ }
+ }
+});
+
+Task("Package")
+ .Description("Packages all nuspec files into nupkg packages.")
+ .WithCriteria(settings.ExecutePackage)
+ .IsDependentOn("UnitTest")
+ .Does(() =>
+{
+ var artifactsPath = Directory(settings.NuGet.ArtifactsPath);
+ var nugetProps = new Dictionary() { {"Configuration", settings.Configuration} };
+
+ CreateDirectory(artifactsPath);
+
+ var nuspecFiles = GetFiles(settings.NuGet.NuSpecFileSpec);
+ foreach(var nsf in nuspecFiles)
+ {
+ Information("Packaging {0}", nsf);
+
+ if (settings.NuGet.UpdateVersion) {
+ VersionUtils.UpdateNuSpecVersion(Context, settings, versionInfo, nsf.ToString());
+ }
+
+ if (settings.NuGet.UpdateLibraryDependencies) {
+ VersionUtils.UpdateNuSpecVersionDependency(Context, settings, versionInfo, nsf.ToString());
+ }
+
+ NuGetPack(nsf, new NuGetPackSettings {
+ Version = versionInfo.ToString(),
+ ReleaseNotes = versionInfo.ReleaseNotes,
+ Symbols = true,
+ Properties = nugetProps,
+ OutputDirectory = artifactsPath
+ });
+ }
+});
+
+Task("Publish")
+ .Description("Publishes all of the nupkg packages to the nuget server. ")
+ .IsDependentOn("Package")
+ .Does(() =>
+{
+ var authError = false;
+
+ if (settings.NuGet.FeedApiKey.ToLower() == "local")
+ {
+ settings.NuGet.FeedUrl = Directory(settings.NuGet.FeedUrl).Path.FullPath;
+ //Information("Using Local repository: {0}", settings.NuGet.FeedUrl);
+ }
+
+ Information("Publishing Packages from {0} to {1} for version {2}", settings.NuGet.ArtifactsPath, settings.NuGet.FeedUrl, versionInfo.ToString());
+
+ // Lets get the list of packages (we can skip anything that is not part of the current version being built)
+ var nupkgFiles = GetFiles(settings.NuGet.NuGetPackagesSpec).Where(x => x.ToString().Contains(versionInfo.ToString())).ToList();
+
+ Information("\t{0}", string.Join("\n\t", nupkgFiles.Select(x => x.GetFilename().ToString()).ToList()));
+
+ foreach (var n in nupkgFiles)
+ {
+ try
+ {
+ NuGetPush(n, new NuGetPushSettings {
+ Source = settings.NuGet.FeedUrl,
+ ApiKey = settings.NuGet.FeedApiKey,
+ ConfigFile = settings.NuGet.NuGetConfig,
+ Verbosity = NuGetVerbosity.Normal
+ });
+ }
+ catch (Exception ex)
+ {
+ Information("\tFailed to published: ", ex.Message);
+
+ if (ex.Message.Contains("403")) { authError = true; }
+ }
+ }
+
+ if (authError && settings.NuGet.FeedApiKey == "VSTS")
+ {
+ Warning("\tYou may need to Configuration Your Credentials.\r\n\t\tCredentialProvider.VSS.exe -Uri {0}", settings.NuGet.FeedUrl);
+ }
+});
+
+Task("UnPublish")
+ .Description("UnPublishes all of the current nupkg packages from the nuget server. Issue: versionToDelete must use : instead of . due to bug in cake")
+ .Does(() =>
+{
+ var v = Argument("versionToDelete", versionInfo.ToString()).Replace(":",".");
+
+ var nuspecFiles = GetFiles(settings.NuGet.NuSpecFileSpec);
+ foreach(var f in nuspecFiles)
+ {
+ Information("UnPublishing {0}", f.GetFilenameWithoutExtension());
+
+ var args = string.Format("delete {0} {1} -Source {2} -NonInteractive",
+ f.GetFilenameWithoutExtension(),
+ v,
+ settings.NuGet.FeedUrl
+ );
+
+ //if (settings.NuGet.FeedApiKey != "VSTS" ) {
+ args = args + string.Format(" -ApiKey {0}", settings.NuGet.FeedApiKey);
+ //}
+
+ if (!string.IsNullOrEmpty(settings.NuGet.NuGetConfig)) {
+ args = args + string.Format(" -Config {0}", settings.NuGet.NuGetConfig);
+ }
+
+ Information("NuGet Command Line: {0}", args);
+ using (var process = StartAndReturnProcess("tools\\nuget.exe", new ProcessSettings {
+ Arguments = args
+ }))
+ {
+ process.WaitForExit();
+ Information("nuget delete exit code: {0}", process.GetExitCode());
+ }
+ }
+});
+
+Task("UpdateVersion")
+ .Description("Updates the version number in the necessary files")
+ .Does(() =>
+{
+ Information("Updating Version to {0}", versionInfo.ToString());
+
+ VersionUtils.UpdateVersion(Context, settings, versionInfo);
+});
+
+Task("IncrementVersion")
+ .Description("Increments the version number and then updates it in the necessary files")
+ .Does(() =>
+{
+ var oldVer = versionInfo.ToString();
+ if (versionInfo.IsPreRelease) versionInfo.PreRelease++; else versionInfo.Build++;
+
+ Information("Incrementing Version {0} to {1}", oldVer, versionInfo.ToString());
+
+ RunTarget("UpdateVersion");
+});
+
+Task("BuildNewVersion")
+ .Description("Increments and Builds a new version")
+ .IsDependentOn("IncrementVersion")
+ .IsDependentOn("Build")
+ .Does(() =>
+{
+});
+
+Task("PublishNewVersion")
+ .Description("Increments, Builds, and publishes a new version")
+ .IsDependentOn("BuildNewVersion")
+ .IsDependentOn("Publish")
+ .Does(() =>
+{
+});
+
+Task("DisplaySettings")
+ .Description("Displays All Settings.")
+ .Does(() =>
+{
+ // Settings will be displayed as they are part of the Setup task
+});
+
+Task("DisplayHelp")
+ .Description("Displays All Settings.")
+ .Does(() =>
+{
+ // Settings will be displayed as they are part of the Setup task
+ SettingsUtils.DisplayHelp(Context);
+});
+
+///////////////////////////////////////////////////////////////////////////////
+// TARGETS
+///////////////////////////////////////////////////////////////////////////////
+
+Task("Default")
+ .Description("This is the default task which will be ran if no specific target is passed in.")
+ .IsDependentOn("Build");
+
+///////////////////////////////////////////////////////////////////////////////
+// EXECUTION
+///////////////////////////////////////////////////////////////////////////////
+
+RunTarget(settings.Target);
\ No newline at end of file
diff --git a/build.osx.sh b/build.osx.sh
new file mode 100644
index 0000000..6e8f207
--- /dev/null
+++ b/build.osx.sh
@@ -0,0 +1,101 @@
+#!/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" http://cakebuild.net/download/bootstrapper/packages
+ if [ $? -ne 0 ]; then
+ echo "An error occured 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 occured 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" $SCRIPT -verbosity=$VERBOSITY -configuration=$CONFIGURATION -target=$TARGET $DRYRUN "${SCRIPT_ARGUMENTS[@]}"
+fi
\ No newline at end of file
diff --git a/build.ps1 b/build.ps1
index d74b339..dd0c32c 100644
--- a/build.ps1
+++ b/build.ps1
@@ -1,43 +1,189 @@
-Param(
- [Parameter(Position=1,Mandatory=0)]
- [string[]]$task_list = @(),
+##########################################################################
+# 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 Experimental
+Tells Cake to use the latest Roslyn release.
+.PARAMETER WhatIf
+Performs a dry run of the build script.
+No tasks will be executed.
+.PARAMETER Mono
+Tells Cake to use the Mono scripting engine.
+.PARAMETER SkipToolPackageRestore
+Skips restoring of packages.
+.PARAMETER ScriptArgs
+Remaining arguments are added here.
+
+.LINK
+http://cakebuild.net
+
+#>
- [Parameter()]
- [string]$BuildMetaData
+[CmdletBinding()]
+Param(
+ [string]$Script = "build.cake",
+ [string]$Target = "Default",
+ [ValidateSet("Release", "Debug")]
+ [string]$Configuration = "Release",
+ [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
+ [string]$Verbosity = "Verbose",
+ [switch]$Experimental,
+ [Alias("DryRun","Noop")]
+ [switch]$WhatIf,
+ [switch]$Mono,
+ [switch]$SkipToolPackageRestore,
+ [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
+ [string[]]$ScriptArgs
)
-$build_file = 'default.ps1'
+[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
+function MD5HashFile([string] $filePath)
+{
+ if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf))
+ {
+ return $null
+ }
-# Properties for the psake build script
-$properties = @{
+ [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()
+ }
+ }
+}
- # Build configuration to use
- "configuration" = "Release";
+Write-Host "Preparing to run build script..."
- # Version number to use if running the Publish build task.
- # This will be read from the command line args
- "version" = $version;
+if(!$PSScriptRoot){
+ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
+}
- # Path to the solution file
- "solution" = 'Nancy.CustomErrors.sln';
+$TOOLS_DIR = Join-Path $PSScriptRoot "tools"
+$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"
- # Folder containing source code
- "source_folder" = '';
+# Should we use mono?
+$UseMono = "";
+if($Mono.IsPresent) {
+ Write-Verbose -Message "Using the Mono based scripting engine."
+ $UseMono = "-mono"
+}
- # Folder to output deployable packages to. This folder should be ignored
- # from any source control, as we dont commit build artifacts to source
- # control
- "deploy_folder" = 'deploy';
+# Should we use the new Roslyn?
+$UseExperimental = "";
+if($Experimental.IsPresent -and !($Mono.IsPresent)) {
+ Write-Verbose -Message "Using experimental version of Roslyn."
+ $UseExperimental = "-experimental"
+}
- # Build number metadata that will be appended to semver numers
- "build_meta" = $BuildMetaData;
-
- "projects" = @(
- "Nancy.CustomErrors")
+# Is this a dry run?
+$UseDryRun = "";
+if($WhatIf.IsPresent) {
+ $UseDryRun = "-dryrun"
+}
+# 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 { (New-Object System.Net.WebClient).DownloadFile("http://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 {
+ (New-Object System.Net.WebClient).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
-import-module .\packages\psake.4.4.1\tools\psake.psm1
+# 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,settingsUtils.cake,versionUtils.cake
+ }
+
+ Write-Verbose -Message "Restoring tools from NuGet..."
+ $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
+
+ if ($LASTEXITCODE -ne 0) {
+ Throw "An error occured while restoring NuGet tools."
+ }
+ else
+ {
+ $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
+ }
+ 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"
+}
-invoke-psake $build_file $task_list -Properties $properties
\ No newline at end of file
+# Start Cake
+Write-Host "Running build script..."
+Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs"
+exit $LASTEXITCODE
\ No newline at end of file
diff --git a/default.ps1 b/default.ps1
deleted file mode 100644
index 069a50c..0000000
--- a/default.ps1
+++ /dev/null
@@ -1,65 +0,0 @@
-Properties {
- $projects = $null
- $configuration = "Release"
- $source_folder = $null
- $solution = $null
- $build_meta = $null
-}
-
-Task Default -Depends Build
-
-
-Task Publish -Depends Package {
- $version = getVersionBase
-
- foreach($project in $projects) {
- Get-ChildItem | Where-Object -FilterScript {
- ($_.Name.Contains("$project.$version")) -and !($_.Name.Contains(".symbols")) -and ($_.Extension -eq '.nupkg')
- } | ForEach-Object {
- exec { nuget push $_.FullName }
- }
- }
-}
-
-Task Package -Depends Test {
- foreach($project in $projects) {
- Get-ChildItem -Path "$project\*.csproj" | ForEach-Object {
- exec { nuget pack -sym $_.FullName -Prop Configuration=$configuration }
- }
- }
-}
-
-Task Test -Depends Build {
- Get-ChildItem $source_folder -Recurse -Include *Tests.csproj | % {
- Exec { & ".\packages\xunit.runners.1.9.2\tools\xunit.console.clr4.exe" "$($_.DirectoryName)\bin\$configuration\$($_.BaseName).dll" /noshadow }
- }
-}
-
-Task Build -Depends Clean,Set-Versions {
- Exec { msbuild "$solution" /t:Build /p:Configuration=$configuration }
-}
-
-Task Clean {
- Exec { msbuild "$solution" /t:Clean /p:Configuration=$configuration }
-}
-
-Task Set-Versions {
- $version = getVersionBase
-
- if ($build_meta) {
- "##teamcity[buildNumber '$version+$build_meta']" | Write-Host
- } else {
- "##teamcity[buildNumber '$version']" | Write-Host
- }
-
- Get-ChildItem -Recurse -Force | Where-Object { $_.Name -eq "AssemblyInfo.cs" } | ForEach-Object {
- (Get-Content $_.FullName) | ForEach-Object {
- ($_ -replace 'AssemblyVersion\(.*\)', ('AssemblyVersion("' + $version + '")')) -replace 'AssemblyFileVersion\(.*\)', ('AssemblyFileVersion("' + $version + '")')
- } | Set-Content $_.FullName -Encoding UTF8
- }
-}
-
-function getVersionBase {
- $versionInfo = (Get-Content "version.json") -join "`n" | ConvertFrom-Json
- "$($versionInfo.major).$($versionInfo.minor).$($versionInfo.patch)";
-}
\ No newline at end of file
diff --git a/nuspec/Nancy.CustomErrors.nuspec b/nuspec/Nancy.CustomErrors.nuspec
new file mode 100644
index 0000000..467e82d
--- /dev/null
+++ b/nuspec/Nancy.CustomErrors.nuspec
@@ -0,0 +1,33 @@
+
+
+
+ Nancy.CustomErrors
+ 2.0.0-pre01
+ Nancy Custom Errors
+ Brendan ravensorb
+ Brendan McMahon
+ https://github.com/bernos/Nancy.CustomErrors
+ Adds exception handling for cases when custom error views cannot be found
+ false
+ Simple custom error handling for Nancyfx projects
+ Copyright 2017
+ Nancyfx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/settings.json b/settings.json
new file mode 100644
index 0000000..3d57486
--- /dev/null
+++ b/settings.json
@@ -0,0 +1,37 @@
+{
+ "version": {
+ "VersionFile": "./version.json",
+ "AssemblyInfoFile": "./Nancy.CustomErrors/Properties/AssemblyInfo.cs",
+ "LoadFrom": "versionfile",
+ "AutoIncrementVersion": false
+ },
+ "build": {
+ "SourcePath": "./src",
+ "SolutionFileSpec": "./*.sln",
+ "TreatWarningsAsErrors": false
+ },
+ "xamarin":{
+ "EnableXamarinIOS": false,
+ "MacAgentIPAddress": "",
+ "MacAgentUserName": "",
+ "MacAgentUserPassword": ""
+ },
+ "test": {
+ "SourcePath": "./tests",
+ "ResultsPath": "./artifacts",
+ "AssemblyFileSpec": "*.Tests.dll",
+ "Framework": "XUnit2"
+ },
+ "nuget": {
+ "NuGetConfig": "./.nuget/NuGet.config",
+ "FeedUrl": "",
+ "FeedAPIKey": "",
+ "ArtifactsPath": "./artifacts/packages",
+ "NuspecPath": "./nuspec",
+ "UpdateVersion": true,
+ "UpdateLibraryDependencies": false,
+ "VersionDependencyForLibrary": "greaterthanorequal",
+ "LibraryNamespaceBase": "",
+ "LibraryMinVersionDependency": ""
+ }
+}
\ No newline at end of file
diff --git a/src/AssemblyInfo.Shared.cs b/src/AssemblyInfo.Shared.cs
new file mode 100644
index 0000000..b7c94c4
--- /dev/null
+++ b/src/AssemblyInfo.Shared.cs
@@ -0,0 +1,36 @@
+// ***********************************************************************
+//
+// Copyright (c) . All rights reserved.
+//
+//
+//
+// ***********************************************************************
+//
+
+using System.Reflection;
+
+// 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: AssemblyCompany("Brendan McMahon")]
+[assembly: AssemblyProduct("Nancy.CustomErrors")]
+[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyConfiguration("")]
+
+// 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("2.0.0")]
+//[assembly: AssemblyFileVersion("2.0.0")]
+
+// 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)]
diff --git a/src/Nancy.CustomErrors.NetStandard1.6/Nancy.CustomErrors.NetStandard1.6.csproj b/src/Nancy.CustomErrors.NetStandard1.6/Nancy.CustomErrors.NetStandard1.6.csproj
new file mode 100644
index 0000000..e5a42d3
--- /dev/null
+++ b/src/Nancy.CustomErrors.NetStandard1.6/Nancy.CustomErrors.NetStandard1.6.csproj
@@ -0,0 +1,15 @@
+
+
+
+ netstandard1.6
+ Nancy.CustomErrors
+ Nancy.CustomErrors
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Nancy.CustomErrors.Shared/CustomErrors.cs b/src/Nancy.CustomErrors.Shared/CustomErrors.cs
new file mode 100644
index 0000000..41cb18f
--- /dev/null
+++ b/src/Nancy.CustomErrors.Shared/CustomErrors.cs
@@ -0,0 +1,87 @@
+// ***********************************************************************
+// Assembly : Nancy.CustomErrors
+// Author :
+// Created : 05-13-2017
+//
+// Last Modified By :
+// Last Modified On : 06-23-2017
+// ***********************************************************************
+//
+// Copyright (c) . All rights reserved.
+//
+//
+// ***********************************************************************
+using System;
+using Nancy.Bootstrapper;
+using Nancy.Responses;
+
+namespace Nancy.CustomErrors
+{
+ ///
+ /// Class CustomErrors.
+ ///
+ public static class CustomErrors
+ {
+ ///
+ /// The configuration
+ ///
+ private static CustomErrorsConfiguration _configuration;
+ ///
+ /// Gets the configuration.
+ ///
+ /// The configuration.
+ public static CustomErrorsConfiguration Configuration
+ {
+ get { return _configuration ?? (_configuration = new CustomErrorsConfiguration()); }
+ }
+
+ ///
+ /// Enables the specified pipelines.
+ ///
+ /// The pipelines.
+ /// The configuration.
+ public static void Enable(IPipelines pipelines, CustomErrorsConfiguration configuration)
+ {
+ Enable(pipelines, configuration, new DefaultJsonSerializer(Nancy.Bootstrapper.NancyBootstrapperLocator.Bootstrapper.GetEnvironment()));
+ }
+
+ ///
+ /// Enables the specified pipelines.
+ ///
+ /// The pipelines.
+ /// The configuration.
+ /// The serializer.
+ ///
+ /// pipelines
+ /// or
+ /// configuration
+ ///
+ public static void Enable(IPipelines pipelines, CustomErrorsConfiguration configuration, ISerializer serializer)
+ {
+ if (pipelines == null)
+ {
+ throw new ArgumentNullException(nameof(pipelines));
+ }
+
+ if (configuration == null)
+ {
+ throw new ArgumentNullException(nameof(configuration));
+ }
+
+ _configuration = configuration;
+
+ pipelines.OnError.AddItemToEndOfPipeline(GetErrorHandler(configuration, serializer));
+ }
+
+ ///
+ /// Gets the error handler.
+ ///
+ /// The configuration.
+ /// The serializer.
+ /// Func<NancyContext, Exception, Response>.
+ private static Func GetErrorHandler(CustomErrorsConfiguration configuration, ISerializer serializer)
+ {
+ return (context, ex) => configuration.HandleError(context, ex, serializer);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Nancy.CustomErrors.Shared/CustomErrorsConfiguration.cs b/src/Nancy.CustomErrors.Shared/CustomErrorsConfiguration.cs
new file mode 100644
index 0000000..7a9b245
--- /dev/null
+++ b/src/Nancy.CustomErrors.Shared/CustomErrorsConfiguration.cs
@@ -0,0 +1,98 @@
+// ***********************************************************************
+// Assembly : Nancy.CustomErrors
+// Author :
+// Created : 05-13-2017
+//
+// Last Modified By :
+// Last Modified On : 05-13-2017
+// ***********************************************************************
+//
+// Copyright (c) . All rights reserved.
+//
+//
+// ***********************************************************************
+using System;
+using System.Collections.Generic;
+
+namespace Nancy.CustomErrors
+{
+ ///
+ /// Class CustomErrorsConfiguration.
+ ///
+ public class CustomErrorsConfiguration
+ {
+ ///
+ /// The not found title
+ ///
+ public string NotFoundTitle = "404 Not Found";
+ ///
+ /// The not found summary
+ ///
+ public string NotFoundSummary = "The requested resource could not be found.";
+ ///
+ /// The forbidden title
+ ///
+ public string ForbiddenTitle = "Forbidden";
+ ///
+ /// The forbidden summary
+ ///
+ public string ForbiddenSummary = "You do not have permission to do that.";
+ ///
+ /// The unauthorized title
+ ///
+ public string UnauthorizedTitle = "Unauthorized";
+ ///
+ /// The unauthorized summary
+ ///
+ public string UnauthorizedSummary = "You do not have permission to do that.";
+ ///
+ /// The error title
+ ///
+ public string ErrorTitle = "Error";
+ ///
+ /// The error summary
+ ///
+ public string ErrorSummary = "An unexpected error occurred.";
+
+ ///
+ /// The always return json
+ ///
+ public bool AlwaysReturnJson = false;
+
+ ///
+ /// If set to true, then we will emit full stack traces in our ErrorResponse
+ ///
+ public bool Debug = false;
+
+ ///
+ /// Converts a thrown exception to the appropriate ErrorResponse. Override this method if you need
+ /// to handle custom exception types, or implement your own error handling logic. The default
+ /// implementation converts all thrown exceptions to a regular ErrorResponse with an HttpStatusCode
+ /// of 500
+ ///
+ /// The context.
+ /// The ex.
+ /// The serializer.
+ /// ErrorResponse.
+ public virtual ErrorResponse HandleError(NancyContext context, Exception ex, ISerializer serializer)
+ {
+ var error = new Error
+ {
+ FullException = ex.ToString(),
+ Message = ex.Message
+ };
+
+ return new ErrorResponse(error, serializer, context.Environment).WithStatusCode(HttpStatusCode.InternalServerError) as ErrorResponse;
+ }
+
+ ///
+ /// Maps different HttpStatusCodes to the appropriate views.
+ ///
+ public IDictionary ErrorViews = new Dictionary
+ {
+ { HttpStatusCode.NotFound, "Error" },
+ { HttpStatusCode.InternalServerError, "Error" },
+ { HttpStatusCode.Forbidden, "Error" }
+ };
+ }
+}
diff --git a/src/Nancy.CustomErrors.Shared/Error.cs b/src/Nancy.CustomErrors.Shared/Error.cs
new file mode 100644
index 0000000..0573b66
--- /dev/null
+++ b/src/Nancy.CustomErrors.Shared/Error.cs
@@ -0,0 +1,33 @@
+// ***********************************************************************
+// Assembly : Nancy.CustomErrors
+// Author :
+// Created : 05-13-2017
+//
+// Last Modified By :
+// Last Modified On : 05-13-2017
+// ***********************************************************************
+//
+// Copyright (c) . All rights reserved.
+//
+//
+// ***********************************************************************
+
+namespace Nancy.CustomErrors
+{
+ ///
+ /// Class Error.
+ ///
+ public class Error
+ {
+ ///
+ /// Gets or sets the message.
+ ///
+ /// The message.
+ public string Message { get; set; }
+ ///
+ /// Gets or sets the full exception.
+ ///
+ /// The full exception.
+ public string FullException { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Nancy.CustomErrors.Shared/ErrorResponse.cs b/src/Nancy.CustomErrors.Shared/ErrorResponse.cs
new file mode 100644
index 0000000..11e1bb2
--- /dev/null
+++ b/src/Nancy.CustomErrors.Shared/ErrorResponse.cs
@@ -0,0 +1,54 @@
+// ***********************************************************************
+// Assembly : Nancy.CustomErrors
+// Author :
+// Created : 05-13-2017
+//
+// Last Modified By :
+// Last Modified On : 05-13-2017
+// ***********************************************************************
+//
+// Copyright (c) . All rights reserved.
+//
+//
+// ***********************************************************************
+using Nancy.Configuration;
+using Nancy.Responses;
+
+namespace Nancy.CustomErrors
+{
+ ///
+ /// Class ErrorResponse.
+ ///
+ public class ErrorResponse : JsonResponse
+ {
+ ///
+ /// The error
+ ///
+ private readonly Error _error;
+ ///
+ /// Gets the error message.
+ ///
+ /// The error message.
+ public string ErrorMessage { get { return _error.Message; } }
+ ///
+ /// Gets the full exception.
+ ///
+ /// The full exception.
+ public string FullException { get { return _error.FullException; } }
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The error.
+ /// The serializer.
+ /// The environment.
+ public ErrorResponse(Error error, ISerializer serializer, INancyEnvironment environment) : base(error, serializer, environment)
+ {
+ if (!CustomErrors.Configuration.Debug)
+ {
+ error.FullException = null;
+ }
+
+ _error = error;
+ }
+ }
+}
diff --git a/src/Nancy.CustomErrors.Shared/ErrorStatusCodeHandler.cs b/src/Nancy.CustomErrors.Shared/ErrorStatusCodeHandler.cs
new file mode 100644
index 0000000..6a13d5f
--- /dev/null
+++ b/src/Nancy.CustomErrors.Shared/ErrorStatusCodeHandler.cs
@@ -0,0 +1,197 @@
+// ***********************************************************************
+// Assembly : Nancy.CustomErrors
+// Author :
+// Created : 05-13-2017
+//
+// Last Modified By :
+// Last Modified On : 05-13-2017
+// ***********************************************************************
+//
+// Copyright (c) . All rights reserved.
+//
+//
+// ***********************************************************************
+using Nancy.ErrorHandling;
+using Nancy.ViewEngines;
+using System;
+using System.IO;
+using System.Linq;
+
+namespace Nancy.CustomErrors
+{
+ ///
+ /// Class ErrorStatusCodeHandler.
+ ///
+ public class ErrorStatusCodeHandler : DefaultViewRenderer, IStatusCodeHandler
+ {
+ ///
+ /// The serializer
+ ///
+ private readonly ISerializer _serializer;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The view factory.
+ public ErrorStatusCodeHandler(IViewFactory viewFactory) : base(viewFactory)
+ {
+ }
+
+ //Made this private as some DI containers like Autofac and Ninject have issues when multiple registered instances of an interface exist and
+ // convention based DI is used for constructors
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The view factory.
+ /// The serializer.
+ private ErrorStatusCodeHandler(IViewFactory viewFactory, ISerializer serializer)
+ : base(viewFactory)
+ {
+ _serializer = serializer;
+ }
+
+ ///
+ /// Handleses the status code.
+ ///
+ /// The status code.
+ /// The context.
+ /// true if XXXX, false otherwise.
+ public bool HandlesStatusCode(HttpStatusCode statusCode, NancyContext context)
+ {
+ return statusCode == HttpStatusCode.NotFound
+ || statusCode == HttpStatusCode.InternalServerError
+ || statusCode == HttpStatusCode.Forbidden
+ || statusCode == HttpStatusCode.Unauthorized;
+ }
+
+ ///
+ /// Handles the specified status code.
+ ///
+ /// The status code.
+ /// The context.
+ public void Handle(HttpStatusCode statusCode, NancyContext context)
+ {
+ var headers = context.Response.Headers.Select(h => Tuple.Create(h.Key, h.Value)).ToArray();
+
+ if (!ShouldRenderFriendlyErrorPage(context))
+ {
+ // Assume a valid error response was built earlier in the request lifecycle
+ // Nothing more for us to do here, so just bail out.
+ if (context.Response is ErrorResponse)
+ {
+ return;
+ }
+
+ var err = new Error
+ {
+ Message = CustomErrors.Configuration.ErrorSummary,
+ };
+
+ if (context.Response is NotFoundResponse)
+ {
+ // Normally we return 404's ourselves so we have an ErrorResponse.
+ // But if no route is matched, Nancy will set a NotFound response itself.
+ // When this happens we still want to return our nice JSON response.
+ err.Message = CustomErrors.Configuration.NotFoundSummary;
+ }
+ else
+ {
+ switch (statusCode)
+ {
+ case HttpStatusCode.Forbidden :
+ case HttpStatusCode.Unauthorized :
+ err.Message = CustomErrors.Configuration.UnauthorizedSummary;
+ break;
+ case HttpStatusCode.NotFound :
+ err.Message = CustomErrors.Configuration.NotFoundSummary;
+ context.Response = new ErrorResponse(new Error
+ {
+ Message = CustomErrors.Configuration.NotFoundSummary
+ }, _serializer, context.Environment);
+ break;
+ }
+ }
+
+ context.Response = new ErrorResponse(err, _serializer, context.Environment).WithHeaders(headers).WithStatusCode(statusCode);
+
+ return;
+ }
+
+ var error = context.Response as ErrorResponse;
+
+ var model = new ErrorViewModel
+ {
+ Details = error == null ? "" : error.FullException,
+ Message = error == null ? "" : error.ErrorMessage
+ };
+
+ switch (statusCode)
+ {
+ case HttpStatusCode.Forbidden:
+ model.Title = CustomErrors.Configuration.ForbiddenTitle;
+ model.Summary = CustomErrors.Configuration.ForbiddenSummary;
+
+ break;
+
+ case HttpStatusCode.Unauthorized:
+ model.Title = CustomErrors.Configuration.UnauthorizedTitle;
+ model.Summary = error == null ? CustomErrors.Configuration.UnauthorizedSummary : error.ErrorMessage;
+
+ break;
+
+ case HttpStatusCode.NotFound:
+ model.Title = CustomErrors.Configuration.NotFoundTitle;
+ model.Summary = CustomErrors.Configuration.NotFoundSummary;
+
+ break;
+ case HttpStatusCode.InternalServerError:
+ model.Title = CustomErrors.Configuration.ErrorTitle;
+ model.Summary = error == null ? CustomErrors.Configuration.ErrorSummary : error.ErrorMessage;
+
+ break;
+ }
+
+ try
+ {
+ context.Response =
+ RenderView(context, CustomErrors.Configuration.ErrorViews[statusCode], model)
+ .WithStatusCode(statusCode)
+ .WithHeaders(headers);
+ }
+ catch(Exception e)
+ {
+ context.Response = new Response
+ {
+ StatusCode = HttpStatusCode.InternalServerError,
+ ContentType = "text/plain",
+ Contents = stream =>
+ {
+ var writer = new StreamWriter(stream) {AutoFlush = true};
+ writer.Write($"Could not locate your error view! Details: {e.Message}");
+ }
+ };
+ }
+ }
+
+ ///
+ /// Shoulds the render friendly error page.
+ ///
+ /// The context.
+ /// true if XXXX, false otherwise.
+ private static bool ShouldRenderFriendlyErrorPage(NancyContext context)
+ {
+ if (CustomErrors.Configuration.AlwaysReturnJson)
+ {
+ return false;
+ }
+
+ if (context.Request.Headers.Accept.OrderByDescending(o => o.Item2)
+ .Any(o => o.Item1 == "application/json" || o.Item1 == "text/json"))
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Nancy.CustomErrors.Shared/ErrorViewModel.cs b/src/Nancy.CustomErrors.Shared/ErrorViewModel.cs
new file mode 100644
index 0000000..457fcf4
--- /dev/null
+++ b/src/Nancy.CustomErrors.Shared/ErrorViewModel.cs
@@ -0,0 +1,38 @@
+// ***********************************************************************
+// Assembly : Nancy.CustomErrors
+// Author :
+// Created : 05-13-2017
+//
+// Last Modified By :
+// Last Modified On : 05-13-2017
+// ***********************************************************************
+//
+// Copyright (c) . All rights reserved.
+//
+//
+// ***********************************************************************
+namespace Nancy.CustomErrors
+{
+ ///
+ /// Class ErrorViewModel.
+ ///
+ public class ErrorViewModel
+ {
+ ///
+ /// Gets or sets the title.
+ ///
+ /// The title.
+ public string Title { get; set; }
+ ///
+ /// Gets or sets the summary.
+ ///
+ /// The summary.
+ public string Summary { get; set; }
+ public string Message { get; set; }
+ ///
+ /// Gets or sets the details.
+ ///
+ /// The details.
+ public string Details { get; set; }
+ }
+}
diff --git a/src/Nancy.CustomErrors.Shared/Nancy.CustomErrors.Shared.projitems b/src/Nancy.CustomErrors.Shared/Nancy.CustomErrors.Shared.projitems
new file mode 100644
index 0000000..01be28a
--- /dev/null
+++ b/src/Nancy.CustomErrors.Shared/Nancy.CustomErrors.Shared.projitems
@@ -0,0 +1,20 @@
+
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+ true
+ 0b0c2e66-9fd4-4475-ab31-81ab2f39f4da
+
+
+ Nancy.CustomErrors.Shared
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Nancy.CustomErrors.Shared/Nancy.CustomErrors.Shared.shproj b/src/Nancy.CustomErrors.Shared/Nancy.CustomErrors.Shared.shproj
new file mode 100644
index 0000000..8cbcca3
--- /dev/null
+++ b/src/Nancy.CustomErrors.Shared/Nancy.CustomErrors.Shared.shproj
@@ -0,0 +1,13 @@
+
+
+
+ 0b0c2e66-9fd4-4475-ab31-81ab2f39f4da
+ 14.0
+
+
+
+
+
+
+
+
diff --git a/src/Nancy.CustomErrors.Shared/ResponseFormatterExtensions.cs b/src/Nancy.CustomErrors.Shared/ResponseFormatterExtensions.cs
new file mode 100644
index 0000000..87d41f3
--- /dev/null
+++ b/src/Nancy.CustomErrors.Shared/ResponseFormatterExtensions.cs
@@ -0,0 +1,39 @@
+// ***********************************************************************
+// Assembly : Nancy.CustomErrors
+// Author :
+// Created : 05-13-2017
+//
+// Last Modified By :
+// Last Modified On : 05-13-2017
+// ***********************************************************************
+//
+// Copyright (c) . All rights reserved.
+//
+//
+// ***********************************************************************
+using System.Linq;
+using Nancy.Responses.Negotiation;
+
+namespace Nancy.CustomErrors
+{
+ ///
+ /// Class ResponseFormatterExtensions.
+ ///
+ public static class ResponseFormatterExtensions
+ {
+ ///
+ /// Ases the error.
+ ///
+ /// The formatter.
+ /// The message.
+ /// The status code.
+ /// Response.
+ public static Response AsError(this IResponseFormatter formatter, string message,
+ HttpStatusCode statusCode = HttpStatusCode.InternalServerError)
+ {
+ var serializer = formatter.SerializerFactory.GetSerializer(new MediaRange("application/json"));
+
+ return new ErrorResponse(new Error {Message = message}, serializer, formatter.Environment).WithStatusCode(statusCode);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Nancy.CustomErrors/Nancy.CustomErrors.csproj b/src/Nancy.CustomErrors/Nancy.CustomErrors.csproj
similarity index 72%
rename from Nancy.CustomErrors/Nancy.CustomErrors.csproj
rename to src/Nancy.CustomErrors/Nancy.CustomErrors.csproj
index b43491d..ba25d4e 100644
--- a/Nancy.CustomErrors/Nancy.CustomErrors.csproj
+++ b/src/Nancy.CustomErrors/Nancy.CustomErrors.csproj
@@ -9,8 +9,11 @@
Properties
Nancy.CustomErrors
Nancy.CustomErrors
- v4.0
+ v4.6.1
512
+
+ ..\..\
+ true
true
@@ -20,6 +23,7 @@
DEBUG;TRACE
prompt
4
+ false
pdbonly
@@ -28,11 +32,11 @@
TRACE
prompt
4
+ false
-
- False
- ..\packages\Nancy.0.23.0\lib\net40\Nancy.dll
+
+ ..\..\packages\Nancy.2.0.0-clinteastwood\lib\net452\Nancy.dll
@@ -43,19 +47,20 @@
-
-
-
-
-
-
-
+
+ Properties\AssemblyInfo.Shared.cs
+
-
+
+ Designer
+
+
+
+
+
\ No newline at end of file
diff --git a/Nancy.CustomErrors.Tests/Properties/AssemblyInfo.cs b/tests/Nancy.CustomErrors.Tests/Properties/AssemblyInfo.cs
similarity index 91%
rename from Nancy.CustomErrors.Tests/Properties/AssemblyInfo.cs
rename to tests/Nancy.CustomErrors.Tests/Properties/AssemblyInfo.cs
index d49ad41..6a8b630 100644
--- a/Nancy.CustomErrors.Tests/Properties/AssemblyInfo.cs
+++ b/tests/Nancy.CustomErrors.Tests/Properties/AssemblyInfo.cs
@@ -31,6 +31,6 @@
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.1.1")]
-[assembly: AssemblyVersion("1.1.1")]
-[assembly: AssemblyFileVersion("1.1.1")]
+// [assembly: AssemblyVersion("2.0.0")]
+[assembly: AssemblyVersion("2.0.0")]
+[assembly: AssemblyFileVersion("2.0.0")]
diff --git a/Nancy.CustomErrors.Tests/Views/Error.html b/tests/Nancy.CustomErrors.Tests/Views/Error.html
similarity index 100%
rename from Nancy.CustomErrors.Tests/Views/Error.html
rename to tests/Nancy.CustomErrors.Tests/Views/Error.html
diff --git a/tests/Nancy.CustomErrors.Tests/app.config b/tests/Nancy.CustomErrors.Tests/app.config
new file mode 100644
index 0000000..0e30424
--- /dev/null
+++ b/tests/Nancy.CustomErrors.Tests/app.config
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/Nancy.CustomErrors.Tests/packages.config b/tests/Nancy.CustomErrors.Tests/packages.config
new file mode 100644
index 0000000..864390e
--- /dev/null
+++ b/tests/Nancy.CustomErrors.Tests/packages.config
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tools/packages.config b/tools/packages.config
new file mode 100644
index 0000000..a4d70bc
--- /dev/null
+++ b/tools/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/tools/settingsUtils.cake b/tools/settingsUtils.cake
new file mode 100644
index 0000000..01a423e
--- /dev/null
+++ b/tools/settingsUtils.cake
@@ -0,0 +1,332 @@
+#addin "Cake.Json"
+
+public class SettingsUtils
+{
+ public static Settings LoadSettings(ICakeContext context)
+ {
+ var settingsFile = context.Argument("settingsFile", ".\\settings.json");
+
+ context.Information("Loading Settings: {0}", settingsFile);
+
+ if (!context.FileExists(settingsFile))
+ {
+ context.Error("Settings File Does Not Exist");
+ return null;
+ }
+
+ var obj = context.DeserializeJsonFromFile(settingsFile);
+
+ obj.SettingsFile = settingsFile;
+
+ // Allow for any overrides
+ obj.Target = context.Argument("target", obj.Target);
+ obj.Configuration = context.Argument("configuration", obj.Configuration);
+ obj.VersionFile = context.Argument("versionFile", obj.VersionFile);
+
+ obj.ExecuteBuild = GetBoolArgument(context, "build", obj.ExecuteBuild);
+ obj.ExecuteBuild = !GetBoolArgument(context, "skipBuild", !obj.ExecuteBuild);
+
+ obj.ExecutePackage = GetBoolArgument(context, "package", obj.ExecutePackage);
+ obj.ExecutePackage = !GetBoolArgument(context, "skipPackage", !obj.ExecutePackage);
+
+ obj.ExecuteUnitTest = GetBoolArgument(context, "unitTest", obj.ExecuteUnitTest);
+ obj.ExecuteUnitTest = !GetBoolArgument(context, "skipUnitTest", !obj.ExecuteUnitTest);
+
+ obj.ExecuteClean = GetBoolArgument(context, "clean", obj.ExecuteClean);
+ obj.ExecuteClean = !GetBoolArgument(context, "skipClean", !obj.ExecuteClean);
+
+ if (obj.Xamarin == null) obj.Xamarin = new XamarinSettings();
+
+ obj.Xamarin.EnableXamarinIOS = GetBoolArgument(context, "enableXamarinIOS", obj.Xamarin.EnableXamarinIOS);
+ obj.Xamarin.MacAgentIPAddress = context.Argument("macAgentIP", obj.Xamarin.MacAgentIPAddress);
+ obj.Xamarin.MacAgentUserName = context.Argument("macUserName", obj.Xamarin.MacAgentUserName);
+ obj.Xamarin.MacAgentUserPassword = context.Argument("macPassword", obj.Xamarin.MacAgentUserPassword);
+
+ if (obj.NuGet == null) obj.NuGet = new NuGetSettings();
+
+ obj.NuGet.FeedUrl = context.Argument("nugetFeed", obj.NuGet.FeedUrl);
+ obj.NuGet.FeedUrl = context.Argument("nugetFeedUrl", obj.NuGet.FeedUrl);
+
+ obj.NuGet.FeedApiKey = context.Argument("nugetApiKey", obj.NuGet.FeedApiKey);
+
+ obj.NuGet.LibraryMinVersionDependency = (context.Argument("dependencyVersion", obj.NuGet.LibraryMinVersionDependency)).Replace(":",".");
+ obj.NuGet.VersionDependencyTypeForLibrary = context.Argument("dependencyType", obj.NuGet.VersionDependencyTypeForLibrary);
+
+ return obj;
+ }
+
+ private static bool GetBoolArgument(ICakeContext context, string argumentName, bool defaultValue)
+ {
+ var result = context.Argument(argumentName, defaultValue.ToString()).ToLower() == "true" ||
+ context.Argument(argumentName, argumentName.ToString()) == "1";
+
+ return result;
+ }
+
+ public static void DisplayHelp(ICakeContext context)
+ {
+ var defaultValues = new Settings();
+
+ context.Information("Command Line Help/Syntax:");
+ context.Information("\t.\\build.ps1 \t\t\t\t(Default: {0})", defaultValues.Target);
+ context.Information("\t\t-Configuration=\t\t(Default: {0})", defaultValues.Configuration);
+ context.Information("\t\t-settingsFile=\t\t(Default: {0})", defaultValues.SettingsFile);
+ context.Information("\t\t-versionFile=\t\t(Default: {0})", defaultValues.VersionFile);
+ context.Information("\t\t-build=<0|1>\t\t\t\t(Default: {0})", defaultValues.ExecuteBuild);
+ context.Information("\t\t-package=<0|1>\t\t\t\t(Default: {0})", defaultValues.ExecutePackage);
+ context.Information("\t\t-unitTest=<0|1>\t\t\t\t(Default: {0})", defaultValues.ExecuteUnitTest);
+ context.Information("\t\t-clean=<0|1>\t\t\t\t(Default: {0})", defaultValues.ExecuteClean);
+ context.Information("\t\t-nugetFeed=\t\t(Default: {0})", defaultValues.NuGet.FeedUrl);
+ context.Information("\t\t-nugetApiKey=\t(Default: {0})", defaultValues.NuGet.FeedApiKey);
+ context.Information("\t\t-dependencyVersion=\t(Default: {0})", defaultValues.NuGet.LibraryMinVersionDependency);
+ context.Information("\t\t-dependencyType=\t\t(Default: {0})", defaultValues.NuGet.VersionDependencyTypeForLibrary);
+ context.Information("\t\t-enableXamarinIOS=<0|1>\t\t\t(Default: {0})", defaultValues.Xamarin.EnableXamarinIOS);
+ context.Information("\t\t-macAgentIP=\t\t(Default: {0})", defaultValues.Xamarin.MacAgentIPAddress);
+ context.Information("\t\t-macUserName=\t\t(Default: {0})", defaultValues.Xamarin.MacAgentUserName);
+ context.Information("\t\t-macPassword=\t\t(Default: {0})", defaultValues.Xamarin.MacAgentUserPassword);
+ context.Information("");
+ context.Information("Examples:");
+ context.Information("\t.\\build Build -Configuration=Release");
+ context.Information("\t.\\build UnitTest -build=0");
+ }
+}
+
+public class Settings
+{
+ public Settings()
+ {
+ ExecuteBuild = true;
+ ExecutePackage = true;
+ ExecuteUnitTest = true;
+ ExecuteClean = true;
+
+ Target = "DisplayHelp";
+ Configuration = "Release";
+ SettingsFile = ".\\settings.json";
+ VersionFile = ".\\version.json";
+
+ Version = new VersionSettings();
+ Build = new BuildSettings();
+ Xamarin = new XamarinSettings();
+ Test = new TestSettings();
+ NuGet = new NuGetSettings();
+ }
+
+ public string Target {get;set;}
+ public string Configuration {get;set;}
+ public string SettingsFile {get;set;}
+ public string VersionFile {get;set;}
+
+ public bool ExecuteBuild {get;set;}
+ public bool ExecutePackage {get;set;}
+ public bool ExecuteUnitTest {get;set;}
+ public bool ExecuteClean {get;set;}
+
+ public VersionSettings Version {get;set;}
+ public BuildSettings Build {get;set;}
+ public TestSettings Test {get;set;}
+ public NuGetSettings NuGet {get;set;}
+ public XamarinSettings Xamarin {get;set;}
+
+ public void Display(ICakeContext context)
+ {
+ context.Information("Settings:");
+
+ context.Information("\tTarget: {0}", Target);
+ context.Information("\tConfiguration: {0}", Configuration);
+ context.Information("\tSettings File: {0}", SettingsFile);
+ context.Information("\tVersion File: {0}", VersionFile);
+
+ context.Information("\tExecute Build: {0}", ExecuteBuild);
+ context.Information("\tExecute Package: {0}", ExecutePackage);
+ context.Information("\tExecute UnitTests: {0}", ExecuteUnitTest);
+ context.Information("\tExecute Clean: {0}", ExecuteClean);
+
+ Version.Display(context);
+ Build.Display(context);
+ Xamarin.Display(context);
+ Test.Display(context);
+ NuGet.Display(context);
+ }
+}
+
+public class VersionSettings
+{
+ public VersionSettings()
+ {
+ LoadFrom = VersionSourceTypes.versionfile;
+ }
+
+ public string VersionFile {get;set;}
+ public string AssemblyInfoFile {get;set;}
+ public VersionSourceTypes LoadFrom {get;set;}
+ public bool AutoIncrementVersion {get;set;}
+
+ public void Display(ICakeContext context)
+ {
+ context.Information("Version Settings:");
+ context.Information("\tVersion File: {0}", VersionFile);
+ context.Information("\tAssemblyInfo File: {0}", AssemblyInfoFile);
+ context.Information("\tLoad From: {0}", LoadFrom);
+ context.Information("\tAutoIncrement Version: {0}", AutoIncrementVersion);
+ }
+}
+
+public class BuildSettings
+{
+ public BuildSettings()
+ {
+ SourcePath = "./source";
+ SolutionFileSpec = "*.sln";
+ TreatWarningsAsErrors = false;
+ MaxCpuCount = 0;
+ }
+
+ public string SourcePath {get;set;}
+ public string SolutionFileSpec {get;set;}
+ public bool TreatWarningsAsErrors {get;set;}
+ public int MaxCpuCount {get;set;}
+
+ public string SolutionFilePath {
+ get {
+ if (SolutionFileSpec.Contains("/")) return SolutionFileSpec;
+
+ return string.Format("{0}{1}{2}", SourcePath, SolutionFileSpec.Contains("*") ? "/**/" : "", SolutionFileSpec);
+ }
+ }
+
+ public void Display(ICakeContext context)
+ {
+ context.Information("Build Settings:");
+ context.Information("\tSource Path: {0}", SourcePath);
+ context.Information("\tSolution File Spec: {0}", SolutionFileSpec);
+ context.Information("\tSolution File Path: {0}", SolutionFilePath);
+ context.Information("\tTreat Warnings As Errors: {0}", TreatWarningsAsErrors);
+ context.Information("\tMax Cpu Count: {0}", MaxCpuCount);
+ }
+}
+
+public class XamarinSettings
+{
+ public XamarinSettings()
+ {
+ EnableXamarinIOS = false;
+ }
+
+ public bool EnableXamarinIOS {get;set;}
+ public string MacAgentIPAddress {get;set;}
+ public string MacAgentUserName {get;set;}
+ public string MacAgentUserPassword {get;set;}
+
+ public void Display(ICakeContext context)
+ {
+ context.Information("Xamarin Settings:");
+ context.Information("\tEnable Xamarin IOS: {0}", EnableXamarinIOS);
+ context.Information("\tMac Agent IP Address: {0}", MacAgentIPAddress);
+ context.Information("\tMac Agent User Name: {0}", MacAgentUserName);
+ //context.Information("\tMac Agent User Password: {0}", MacAgentUserPassword);
+ }
+}
+
+public class TestSettings
+{
+ public TestSettings()
+ {
+ SourcePath = "./tests";
+ ResultsPath = "./tests";
+ AssemblyFileSpec = "*.UnitTests.dll";
+ Framework = TestFrameworkTypes.NUnit3;
+ }
+
+ public string SourcePath {get;set;}
+ public string ResultsPath {get;set;}
+ public string AssemblyFileSpec {get;set;}
+ public TestFrameworkTypes Framework {get;set;}
+
+ public void Display(ICakeContext context)
+ {
+ context.Information("Test Settings:");
+ context.Information("\tSource Path: {0}", SourcePath);
+ context.Information("\tResults Path: {0}", ResultsPath);
+ context.Information("\tTest Assemploes File Spec: {0}", AssemblyFileSpec);
+ }
+}
+
+public class NuGetSettings
+{
+ public NuGetSettings()
+ {
+ NuSpecPath = "./nuspec";
+ NuGetConfig = "./.nuget/NuGet.Config";
+ ArtifactsPath = "artifacts/packages";
+ UpdateVersion = false;
+ VersionDependencyTypeForLibrary = VersionDependencyTypes.none;
+ UpdateLibraryDependencies = false;
+ LibraryNamespaceBase = null;
+ LibraryMinVersionDependency = null;
+ }
+
+ public string NuGetConfig {get;set;}
+ public string FeedUrl {get;set;}
+ public string FeedApiKey {get;set;}
+ public string NuSpecPath {get;set;}
+ public string ArtifactsPath {get;set;}
+ public bool UpdateVersion {get;set;}
+ public VersionDependencyTypes VersionDependencyTypeForLibrary {get;set;}
+ public bool UpdateLibraryDependencies {get;set;}
+ public string LibraryNamespaceBase {get;set;}
+ public string LibraryMinVersionDependency {get;set;}
+
+ public string NuSpecFileSpec {
+ get {
+ return string.Format("{0}/**/*.nuspec", NuSpecPath);
+ }
+ }
+
+ public string NuGetPackagesSpec {
+ get {
+ return string.Format("{0}/*.nupkg", ArtifactsPath);
+ }
+ }
+
+ public void Display(ICakeContext context)
+ {
+ context.Information("NuGet Settings:");
+ context.Information("\tNuGet Config: {0}", NuGetConfig);
+ context.Information("\tFeed Url: {0}", FeedUrl);
+ //context.Information("\tFeed API Key: {0}", FeedApiKey);
+ context.Information("\tNuSpec Path: {0}", NuSpecPath);
+ context.Information("\tNuSpec File Spec: {0}", NuSpecFileSpec);
+ context.Information("\tArtifacts Path: {0}", ArtifactsPath);
+ context.Information("\tNuGet Packages Spec: {0}", NuGetPackagesSpec);
+ context.Information("\tUpdate Version: {0}", UpdateVersion);
+ context.Information("\tUpdate Library Dependencies: {0}", UpdateLibraryDependencies);
+ context.Information("\tForce Version Match: {0}", VersionDependencyTypeForLibrary);
+ context.Information("\tLibrary Namespace Base: {0}", LibraryNamespaceBase);
+ context.Information("\tLibrary Min Version Dependency: {0}", LibraryMinVersionDependency);
+ }
+}
+
+public enum VersionDependencyTypes {
+ none,
+ exact,
+ greaterthan,
+ greaterthanorequal,
+ lessthan
+}
+
+public enum VersionSourceTypes {
+ none,
+ versionfile,
+ assemblyinfo,
+ git,
+ tfs
+}
+
+public enum TestFrameworkTypes {
+ none,
+ NUnit2,
+ NUnit3,
+ XUnit,
+ XUnit2
+}
\ No newline at end of file
diff --git a/tools/versionUtils.cake b/tools/versionUtils.cake
new file mode 100644
index 0000000..7d9908d
--- /dev/null
+++ b/tools/versionUtils.cake
@@ -0,0 +1,236 @@
+#addin "Cake.Json"
+#addin "Cake.FileHelpers"
+
+#tool nuget:?package=GitVersion.CommandLine
+
+public class VersionUtils
+{
+ public static VersionInfo LoadVersion(ICakeContext context, Settings settings)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException("context");
+ }
+
+ VersionInfo verInfo = null;
+
+ switch (settings.Version.LoadFrom)
+ {
+ case VersionSourceTypes.none:
+ break;
+ case VersionSourceTypes.versionfile:
+ verInfo = LoadVersionFromJson(context, settings.Version.VersionFile);
+ break;
+ case VersionSourceTypes.assemblyinfo:
+ verInfo = LoadVersionFromAssemblyInfo(context, settings.Version.AssemblyInfoFile);
+ break;
+ case VersionSourceTypes.git:
+ verInfo = LoadVersionFromGit(context);
+ break;
+ case VersionSourceTypes.tfs:
+ //verInfo = LoadVersionFromTfs(context);
+ break;
+ }
+
+ if (verInfo != null)
+ {
+ verInfo.CakeVersion = typeof(ICakeContext).Assembly.GetName().Version.ToString();
+ }
+
+ return verInfo;
+ }
+
+ private static VersionInfo LoadVersionFromJson(ICakeContext context, string versionFile)
+ {
+ context.Information("Loading Version Info From File: {0}", versionFile);
+ if (string.IsNullOrEmpty(versionFile) || !context.FileExists(versionFile))
+ {
+ context.Error("Version File Does Not Exist");
+ return null;
+ }
+
+ var obj = context.DeserializeJsonFromFile(versionFile);
+
+ return obj;
+ }
+
+ private static VersionInfo LoadVersionFromAssemblyInfo(ICakeContext context, string assemblyInfoFile)
+ {
+ context.Information("Fetching Version Info from AssemblyInfo File: {0}", assemblyInfoFile);
+
+ if (!string.IsNullOrEmpty(assemblyInfoFile) || !context.FileExists(assemblyInfoFile))
+ {
+ context.Error("AssemblyInfo file does not exist");
+ return null;
+ }
+
+ try {
+ var assemblyInfo = context.ParseAssemblyInfo(assemblyInfoFile);
+ var v = Version.Parse(assemblyInfo.AssemblyVersion);
+
+ var verInfo = new VersionInfo {
+ Major = v.Major,
+ Minor = v.Minor,
+ Build = v.Build,
+ Semantic = assemblyInfo.AssemblyInformationalVersion,
+ Milestone = string.Concat("v", v.ToString())
+ };
+
+ return verInfo;
+ }
+ catch {}
+
+ return null;
+ }
+
+ private static VersionInfo LoadVersionFromGit(ICakeContext context)
+ {
+ context.Information("Fetching Verson Infop from Git");
+
+ try {
+ GitVersion assertedVersions = context.GitVersion(new GitVersionSettings
+ {
+ OutputType = GitVersionOutput.Json,
+ });
+
+ var verInfo = new VersionInfo {
+ Major = assertedVersions.Major,
+ Minor = assertedVersions.Minor,
+ Build = assertedVersions.Patch,
+ Semantic = assertedVersions.LegacySemVerPadded,
+ Milestone = string.Concat("v", assertedVersions.MajorMinorPatch)
+ };
+
+ context.Information("Calculated Semantic Version: {0}", verInfo.Semantic);
+
+ return verInfo;
+ } catch {}
+
+ return null;
+ }
+
+ public static void UpdateVersion(ICakeContext context, Settings settings, VersionInfo verInfo)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException("context");
+ }
+
+ if (!string.IsNullOrEmpty(settings.Version.VersionFile) && context.FileExists(settings.Version.VersionFile))
+ {
+ context.Information("Updating Version File {0}", settings.Version.VersionFile);
+
+ context.SerializeJsonToFile(settings.Version.VersionFile, verInfo);
+ }
+
+ if (!string.IsNullOrEmpty(settings.Version.AssemblyInfoFile) && context.FileExists(settings.Version.AssemblyInfoFile))
+ {
+ context.Information("Updating Assembly Info File {0}", settings.Version.AssemblyInfoFile);
+
+ context.ReplaceRegexInFiles(settings.Version.AssemblyInfoFile, "AssemblyVersion\\(.*\\)", string.Format("AssemblyVersion(\"{0}\")", verInfo.ToString(false)));
+ context.ReplaceRegexInFiles(settings.Version.AssemblyInfoFile, "AssemblyFileVersion\\(.*\\)", string.Format("AssemblyFileVersion(\"{0}\")", verInfo.ToString(false)));
+ }
+ }
+
+ public static void UpdateNuSpecVersion(ICakeContext context, Settings settings, VersionInfo verInfo, FilePath nuspecFile)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException("context");
+ }
+
+ var xpq = string.Format("/n:package/n:metadata/n:version");
+
+ context.Information("\tUpdating Version in Nuspec File {0} to {1}", nuspecFile, verInfo.ToString());
+
+ try {
+ context.XmlPoke(nuspecFile, xpq, verInfo.ToString(), new XmlPokeSettings {
+ PreserveWhitespace = true
+ , Namespaces = new Dictionary {
+ { /* Prefix */ "n", /* URI */ "http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd"}
+ }
+ });
+ } catch {} // Its ok to throw these away as it most likely means the file didn't exist or the XPath didn't find any nodes
+ }
+
+ public static void UpdateNuSpecVersionDependency(ICakeContext context, Settings settings, VersionInfo verInfo, FilePath nuspecFile)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException("context");
+ }
+
+ if (string.IsNullOrEmpty(settings.NuGet.LibraryNamespaceBase)) return;
+
+ var xpq = string.Format("/n:package/n:metadata/n:dependencies//n:dependency[starts-with(@id, '{0}')]/@version", settings.NuGet.LibraryNamespaceBase);
+
+ var replacementStr = !string.IsNullOrEmpty(settings.NuGet.LibraryMinVersionDependency) ? settings.NuGet.LibraryMinVersionDependency : verInfo.ToString();
+
+ switch (settings.NuGet.VersionDependencyTypeForLibrary)
+ {
+ case VersionDependencyTypes.none: break;
+ case VersionDependencyTypes.exact: replacementStr = string.Format("[{0}]", replacementStr); break;
+ case VersionDependencyTypes.greaterthan: replacementStr = string.Format("(,{0})", replacementStr); break;
+ case VersionDependencyTypes.greaterthanorequal: replacementStr = string.Format("(,{0}]", replacementStr); break;
+ case VersionDependencyTypes.lessthan: replacementStr = string.Format("({0},)", replacementStr); break;
+ }
+
+ context.Information("\tUpdating Version for {0} Namespace Assemblies in Nuspec File {1} to {2}", settings.NuGet.LibraryNamespaceBase, nuspecFile, replacementStr);
+
+ try {
+ context.XmlPoke(nuspecFile, xpq, replacementStr, new XmlPokeSettings {
+ PreserveWhitespace = true
+ , Namespaces = new Dictionary {
+ { /* Prefix */ "n", /* URI */ "http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd"}
+ }
+ });
+ } catch {} // Its ok to throw these away as it most likely means the file didn't exist or the XPath didn't find any nodes
+ }
+}
+
+public class VersionInfo
+{
+ [Newtonsoft.Json.JsonProperty("major")]
+ public int Major {get;set;}
+ [Newtonsoft.Json.JsonProperty("minor")]
+ public int Minor {get;set;}
+ [Newtonsoft.Json.JsonProperty("build")]
+ public int Build {get;set;}
+ [Newtonsoft.Json.JsonProperty("preRelease")]
+ public int? PreRelease {get;set;}
+ [Newtonsoft.Json.JsonProperty("releaseNotes")]
+ public string[] ReleaseNotes {get;set;}
+
+ [Newtonsoft.Json.JsonIgnore]
+ public string Semantic {get;set;}
+ [Newtonsoft.Json.JsonIgnore]
+ public string Milestone {get;set;}
+ [Newtonsoft.Json.JsonIgnore]
+ public string CakeVersion {get;set;}
+
+ [Newtonsoft.Json.JsonIgnore]
+ public bool IsPreRelease { get { return PreRelease != null && PreRelease != 0; } }
+
+ public new string ToString(bool includePreRelease = true)
+ {
+ var str = string.Format("{0:#0}.{1:#0}.{2:#0}", Major, Minor, Build);
+ if (IsPreRelease && includePreRelease) str += string.Format("-pre{0:00}", PreRelease);
+
+ return str;
+ }
+
+ public void Display(ICakeContext context)
+ {
+ context.Information("Version:");
+ context.Information("\tMajor: {0}", Major);
+ context.Information("\tMinor: {0}", Minor);
+ context.Information("\tBuild: {0}", Build);
+ context.Information("\tIs PreRelease: {0}", IsPreRelease);
+ context.Information("\tPreRelease: {0}", PreRelease);
+ context.Information("\tSemantic: {0}", Semantic);
+ context.Information("\tMilestone: {0}", Milestone);
+ context.Information("\tCake Version: {0}", CakeVersion);
+
+ if (ReleaseNotes != null) context.Information("\tRelease Notes: {0}", ReleaseNotes);
+ }
+}
\ No newline at end of file
diff --git a/version.json b/version.json
index ff2064e..697e456 100644
--- a/version.json
+++ b/version.json
@@ -1,5 +1 @@
-{
- "major" : 1,
- "minor" : 2,
- "patch" : 0
-}
\ No newline at end of file
+{"major":2,"minor":0,"build":0,"preRelease":1,"releaseNotes":null}
\ No newline at end of file