diff --git a/.gitignore b/.gitignore index c6b8abc..4c32f8f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,9 @@ obj/ TestResults/ *.csproj.user *.suo -*.nupkg \ No newline at end of file +*.nupkg + +# project.json +*.lock.json +.vs +*.user \ No newline at end of file diff --git a/README.md b/README.md index 8259e0f..7a2ef14 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![Build status](https://ci.appveyor.com/api/projects/status/kek3h7gflo3qqidb?svg=true)](https://ci.appveyor.com/project/maxhauser/semver) + A semantic version library for .Net =================================== diff --git a/Semver.Test/Semver.Test.csproj b/Semver.Test/Semver.Test.csproj deleted file mode 100644 index e7668d3..0000000 --- a/Semver.Test/Semver.Test.csproj +++ /dev/null @@ -1,90 +0,0 @@ - - - - Debug - AnyCPU - {EAE17B6B-5380-4017-8046-1757EB77DF53} - Library - Properties - Semver.Test - Semver.Test - v4.0 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - - - - - {95b2542c-e371-4ab4-9e2d-b2665cbbd629} - Semver - - - - - - - False - - - False - - - False - - - False - - - - - - - - \ No newline at end of file diff --git a/Semver.sln b/Semver.sln index aad537c..c1228d9 100644 --- a/Semver.sln +++ b/Semver.sln @@ -1,30 +1,32 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semver", "Semver\Semver.csproj", "{95B2542C-E371-4AB4-9E2D-B2665CBBD629}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semver.Test", "Semver.Test\Semver.Test.csproj", "{EAE17B6B-5380-4017-8046-1757EB77DF53}" -EndProject +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{AC069663-5FE9-438A-A9F4-C5293D695D98}" ProjectSection(SolutionItems) = preProject License.txt = License.txt README.md = README.md EndProjectSection EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Semver", "src\Semver\Semver.xproj", "{DA3E84C8-A960-420C-A85A-718005AACC36}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Semver.Test", "test\Semver.Test\Semver.Test.xproj", "{DA03E4C4-CB6C-447B-B617-15B5689E9029}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {95B2542C-E371-4AB4-9E2D-B2665CBBD629}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {95B2542C-E371-4AB4-9E2D-B2665CBBD629}.Debug|Any CPU.Build.0 = Debug|Any CPU - {95B2542C-E371-4AB4-9E2D-B2665CBBD629}.Release|Any CPU.ActiveCfg = Release|Any CPU - {95B2542C-E371-4AB4-9E2D-B2665CBBD629}.Release|Any CPU.Build.0 = Release|Any CPU - {EAE17B6B-5380-4017-8046-1757EB77DF53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EAE17B6B-5380-4017-8046-1757EB77DF53}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EAE17B6B-5380-4017-8046-1757EB77DF53}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EAE17B6B-5380-4017-8046-1757EB77DF53}.Release|Any CPU.Build.0 = Release|Any CPU + {DA3E84C8-A960-420C-A85A-718005AACC36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA3E84C8-A960-420C-A85A-718005AACC36}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA3E84C8-A960-420C-A85A-718005AACC36}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA3E84C8-A960-420C-A85A-718005AACC36}.Release|Any CPU.Build.0 = Release|Any CPU + {DA03E4C4-CB6C-447B-B617-15B5689E9029}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA03E4C4-CB6C-447B-B617-15B5689E9029}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA03E4C4-CB6C-447B-B617-15B5689E9029}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA03E4C4-CB6C-447B-B617-15B5689E9029}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Semver/Semver.csproj b/Semver/Semver.csproj deleted file mode 100644 index 89b1af0..0000000 --- a/Semver/Semver.csproj +++ /dev/null @@ -1,51 +0,0 @@ - - - - - Debug - AnyCPU - {95B2542C-E371-4AB4-9E2D-B2665CBBD629} - Library - Properties - Semver - Semver - v4.0 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - bin\Debug\Semver.XML - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Semver.XML - - - - - - - - - - - \ No newline at end of file diff --git a/Semver/Semver.nuspec b/Semver/Semver.nuspec deleted file mode 100644 index 2f6cb83..0000000 --- a/Semver/Semver.nuspec +++ /dev/null @@ -1,23 +0,0 @@ - - - - semver - 1.1.1 - Semantic versioning - Max Hauser - Max Hauser - https://github.com/maxhauser/semver/ - http://max.mit-license.org/ - false - A semver implementation in .Net based on the v2.0.0 of the spec found at http://semver.org/. - Copyright 2013 - semver semantic version - - - - - - - - - \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..85a074d --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,58 @@ +version: 2.0.{build} +os: Visual Studio 2015 + +configuration: Release + +pull_requests: + do_not_increment_build_number: true + +init: + - git config --global core.autocrlf true + - ps: $env:GIT_HASH=$env:APPVEYOR_REPO_COMMIT.Substring(0, 10) + - ps: If ("$env:APPVEYOR_REPO_BRANCH" -ne "master") { $env:VERSION_SUFFIX="-pre" } + +assembly_info: + patch: true + file: AssemblyInfo.* + assembly_version: "{version}.0" + assembly_file_version: "{version}.0" + assembly_informational_version: "{version}$(VERSION_SUFFIX) $(GIT_HASH)" + +before_build: + - ps: >- + Get-ChildItem -Path .\ -Filter project.json -Recurse -Name | + ForEach { + $content = Get-Content "$_" + $content = $content.Replace("99.99.99-dev", "$($env:APPVEYOR_BUILD_VERSION)$($env:VERSION_SUFFIX)") + Set-Content "$_" $content -Encoding UTF8 + } + - dotnet restore -v Minimal + +build_script: + - dotnet pack "src\Semver" -c Release -o artifacts + +test_script: + - dotnet test "test\Semver.Test" + +artifacts: + - path: artifacts\*.nupkg + name: ReleaseArtifacts + +deploy: + - provider: Environment + name: NuGet + on: + branch: master +# - provider: GitHub +# auth_token: +# secure: +# draft: true +# on: +# branch: master +# appveyor_repo_tag: true + +#notifications: +# - provider: Slack +# channel: '#notifications' +# auth_token: +# secure: \ No newline at end of file diff --git a/global.json b/global.json new file mode 100644 index 0000000..487e388 --- /dev/null +++ b/global.json @@ -0,0 +1,9 @@ +{ + "projects": [ + "src", + "test" + ], + "sdk": { + "version": "1.0.0-preview2-003121" + } +} diff --git a/myget.include.ps1 b/myget.include.ps1 deleted file mode 100644 index d656cd6..0000000 --- a/myget.include.ps1 +++ /dev/null @@ -1,1689 +0,0 @@ -# MIT LICENSE (https://github.com/peters/myget/blob/master/myget.include.ps1) - -# Copyright Peter Rekdal Sunde 2013 - -# Thanks to https://github.com/Squirrel/Squirrel.Windows - -# You can update myget.include.ps1 by running the following command: -# .\myget.include.ps1 -updateSelf 1 - -param( - [bool] $updateSelf = $false -) - -# Default error action when a MyGet-* function throws an error -$ErrorActionPreference = "Stop" - -# Prerequisites (You should add .buildtools to your .(git|hg)ignore) -$buildRunnerToolsFolder = Split-Path $MyInvocation.MyCommand.Path -$buildRunnerToolsFolder = Join-Path $buildRunnerToolsFolder ".buildtools" - -# Miscellaneous - -function MyGet-HipChatRoomMessage { - # copyright: https://github.com/lholman/hipchat-ps - - param( - [parameter(Position = 0, Mandatory = $True)] - [string]$apitoken, - [parameter(Position = 1, Mandatory = $True)] - [string]$roomid, - [parameter(Position = 2, Mandatory = $False)] - [string]$from = $env:COMPUTERNAME, - [parameter(Position = 3, Mandatory = $True)] - [string]$message, - [parameter(Position = 4, Mandatory = $False)] - [string]$colour = "yellow", - [parameter(Position = 5, Mandatory = $False)] - [string]$notify = "1", - [parameter(Position = 6, Mandatory = $False)] - [string]$apihost = "api.hipchat.com" - ) - - #Replace naked URL's with hyperlinks - $regex = [regex] "((www\.|(http|https|ftp|news|file)+\:\/\/)[_.a-z0-9-]+\.[a-z0-9\/_:@=.+?,##%&~-]*[^.|\'|\# |!|\(|?|,| |>|<|;|\)])" - $message = $regex.Replace($message, "`$1").Replace("href=`"www", "href=`"http://www") - - #Do the HTTP POST to HipChat - $post = "auth_token=$apitoken&room_id=$roomid&from=$from&color=$colour&message=$message¬ify=$notify" - Write-Debug "post = $post" - Write-Debug "https://$apihost/v1/rooms/message" - $webRequest = [System.Net.WebRequest]::Create("https://$apihost/v1/rooms/message") - $webRequest.ContentType = "application/x-www-form-urlencoded" - $postStr = [System.Text.Encoding]::UTF8.GetBytes($post) - $webrequest.ContentLength = $postStr.Length - $webRequest.Method = "POST" - $requestStream = $webRequest.GetRequestStream() - $requestStream.Write($postStr, 0,$postStr.length) - $requestStream.Close() - - [System.Net.WebResponse] $resp = $webRequest.GetResponse(); - $rs = $resp.GetResponseStream(); - [System.IO.StreamReader] $sr = New-Object System.IO.StreamReader -argumentList $rs; - $result = $sr.ReadToEnd(); - - return $result | Format-Table - -} - -function MyGet-AssemblyVersion-Set { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$projectFolder, - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [ValidatePattern("^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?$")] - [string]$version - ) - - function Write-VersionAssemblyInfo { - Param( - [string] - $version, - - [string] - $assemblyInfo - ) - - $numberOfReplacements = 0 - $newContent = Get-Content $assemblyInfo | %{ - $regex = "(Assembly(?:File|Informational)?Version)\(`"\d+\.\d+\.\d+`"\)" - $newString = $_ - if ($_ -match $regex) { - $numberOfReplacements++ - $newString = $_ -replace $regex, "`$1(`"$version`")" - } - $newString - } - - if ($numberOfReplacements -ne 3) { - MyGet-Die "Expected to replace the version number in 3 places in AssemblyInfo.cs (AssemblyVersion, AssemblyFileVersion, AssemblyInformationalVersion) but actually replaced it in $numberOfReplacements" - } - - $newContent | Set-Content $assemblyInfo -Encoding UTF8 - } - - $projectFolder = Split-Path -parent $projectFolder - $assemblyInfo = Get-ChildItem -Path $projectFolder -Filter "AssemblyInfo.cs" -Recurse - $assemblyInfO = $assemblyInfo[0].FullName - - MyGet-Write-Diagnostic "New assembly version: $version" - - Write-VersionAssemblyInfo -assemblyInfo $assemblyInfo -version $version - -} - -function MyGet-AssemblyInfo { - # https://github.com/peters/assemblyinfo/blob/develop/getassemblyinfo.ps1 - - # Sample output: - # - # ProcessorArchitecture : AnyCpu - # PEFormat : PE32 - # Filename : D:\sample.solution.mixedplatforms\1.0.0\x86\Release\v4.5\sample.solution.mixedplatforms.x86.exe - # ModuleKind : Console - # ModuleAttributes : {ILOnly, Required32Bit} - # MinorRuntimeVersion : 5 - # MajorRuntimeVersion : 2 - # ModuleCharacteristics : {HighEntropyVA, DynamicBase, NoSEH, NXCompat...} - # TargetFramework : NET45 - - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string] $filename - ) - - if(-not (Test-Path -Path $filename)) { - Write-Error "Could not find file: $filename" - exit 1 - } - - function AssemblyInfo { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [uint32] $peFormat = $null, - [parameter(Position = 1, Mandatory = $false, ValueFromPipeline = $true)] - [uint32] $attributes = $null, - [parameter(Position = 2, Mandatory = $false, ValueFromPipeline = $true)] - [uint32] $machine = $null, - [parameter(Position = 3, Mandatory = $false, ValueFromPipeline = $true)] - [uint16] $characteristics = $null, - [parameter(Position = 4, Mandatory = $false, ValueFromPipeline = $true)] - [object] $optionalHeaders = $null, - [parameter(Position = 5, Mandatory = $false, ValueFromPipeline = $true)] - [uint32] $majorRuntimeVersion = $null, - [parameter(Position = 6, Mandatory = $false, ValueFromPipeline = $true)] - [uint32] $minorRuntimeVersion = $null, - [parameter(Position = 7, Mandatory = $false, ValueFromPipeline = $true)] - [string] $targetFramework = $null - ) - - $assemblyInfo = @{} - - # Major/minor - $assemblyInfo.Filename = $filename - $assemblyInfo.MajorRuntimeVersion = $majorRuntimeVersion - $assemblyInfo.MinorRuntimeVersion = $minorRuntimeVersion - $assemblyInfo.TargetFramework = $targetFramework - $assemblyInfo.ModuleKind = GetModuleKind -characteristics $characteristics -subSystem $optionalHeaders.SubSystem - $assemblyInfo.ModuleCharacteristics = GetModuleCharacteristics -characteristics $characteristics - $assemblyInfo.ModuleAttributes = GetModuleAttributes -attributes $attributes - - ## PeFormat - if($peFormat -eq 0x20b) { - $assemblyInfo.PEFormat = "PE32Plus" - } elseif($peFormat -eq 0x10b) { - $assemblyInfo.PEFormat = "PE32" - } - - ## ProcessorArchitecture - $assemblyInfo.ProcessorArchitecture = "Unknown" - - switch -Exact ($machine) { - 0x014c { - $assemblyInfo.ProcessorArchitecture = "x86" - if($assemblyInfo.ModuleAttributes -contains "ILOnly") { - $assemblyInfo.ProcessorArchitecture = "AnyCpu" - } - } - 0x8664 { - $assemblyInfo.ProcessorArchitecture = "x64" - } - 0x0200 { - $assemblyInfo.ProcessorArchitecture = "IA64" - } - 0x01c4 { - $assemblyInfo.ProcessorArchitecture = "ARMv7" - } - default { - if($assemblyInfo.PEFormat -eq "PE32PLUS") { - $assemblyInfo.ProcessorArchitecture = "x64" - } elseif($assemblyInfo.PEFormat -eq "PE32") { - $assemblyInfo.ProcessorArchitecture = "x86" - } - } - } - - return New-Object -TypeName PSObject -Property $assemblyInfo - } - - function GetModuleKind { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [uint32] $characteristics, - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [uint32] $subSystem - ) - - # ImageCharacteristics.Dll - if($characteristics -eq ($characteristics -bor 0x2000)) { - return "Dll" - } - - # SubSystem.WindowsGui || SubSystem.WindowsCeGui - if($subSystem -eq 0x2 -or $subSystem -eq 0x9) { - return "WinExe" - } - - return "Console" - } - - function GetModuleCharacteristics { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [uint16] $characteristics - ) - - $moduleCharacteristics = @() - - if($characteristics -eq ($characteristics -bor 0x0020)) { - $moduleCharacteristics += "HighEntropyVA" - } - - if($characteristics -eq ($characteristics -bor 0x0040)) { - $moduleCharacteristics += "DynamicBase" - } - - if($characteristics -eq ($characteristics -bor 0x0400)) { - $moduleCharacteristics += "NoSEH" - } - - if($characteristics -eq ($characteristics -bor 0x0100)) { - $moduleCharacteristics += "NXCompat" - } - - if($characteristics -eq ($characteristics -bor 0x1000)) { - $moduleCharacteristics += "AppContainer" - } - - if($characteristics -eq ($characteristics -bor 0x8000)) { - $moduleCharacteristics += "TerminalServerAware" - } - - return $moduleCharacteristics - } - - function GetModuleAttributes { - param( - [parameter(Position = 0, Mandatory = $false, ValueFromPipeline = $true)] - [uint32] $attributes = $null - ) - - $moduleAttributes = @() - - if($attributes -eq ($attributes -bor 0x1)) { - $moduleAttributes += "ILOnly" - } - - if($attributes -eq ($attributes -bor 0x2)) { - $moduleAttributes += "Required32Bit" - } - - if($attributes -eq ($attributes -bor 0x8)) { - $moduleAttributes += "StrongNameSigned" - } - - if($attributes -eq ($attributes -bor 0x00020000)) { - $moduleAttributes += "Preferred32Bit" - } - - return $moduleAttributes - - } - - function Advance { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [System.IO.Stream] $stream, - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [int] $count - ) - - $stream.Seek($count, [System.IO.SeekOrigin]::Current) | Out-Null - } - - # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L238 - function ReadZeroTerminatedString { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [System.IO.BinaryReader] $binaryReader, - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [int] $length - ) - - $read = 0 - $buffer = New-Object char[] $length - $bytes = $binaryReader.ReadBytes($length) - while($read -lt $length) { - $current = $bytes[$read] - if($current -eq 0) { - break - } - - $buffer[$read++] = $current - } - - return New-Object string ($buffer, 0, $read) - } - - # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/Image.cs#L98 - # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/Image.cs#L107 - # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/Image.cs#L124 - function ResolveVirtualAddress { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [uint32] $rva, - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [object[]] $sections - ) - - $section = $null - - $sections | ForEach-Object { - if($rva -ge $_.VirtualAddress -and $rva -lt $_.VirtualAddress + $_.SizeOfRawData) { - $section = $_ - return - } - } - - if($section -eq $null) { - Write-Error "Unable to resolve virtual address for rva address: " $rva - exit 1 - } - - return [System.Convert]::ToUInt32($rva + $section.PointerToRawData - $section.VirtualAddress) - } - - # # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/Image.cs#L53 - function MoveTo { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [System.IO.Stream] $stream, - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [object] $dataDirectory, - [parameter(Position = 2, Mandatory = $true, ValueFromPipeline = $true)] - [object] $sections - ) - - $stream.Position = ResolveVirtualAddress -rva ([uint32] $dataDirectory.VirtualAddress) -sections $sections - } - - # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/BinaryStreamReader.cs#L46 - function ReadDataDirectory { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [System.IO.BinaryReader] $binaryReader - ) - - $dataDirectory = @{} - $dataDirectory.VirtualAddress = $binaryReader.ReadUInt32() - $dataDirectory.VirtualSize = $binaryReader.ReadUInt32() - $dataDirectory.IsZero = $dataDirectory.VirtualAddress -eq 0 -and $dataDirectory.VirtualSize -eq 0 - - return New-Object -TypeName PSObject -Property $dataDirectory - } - - # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L140 - function ReadOptionalHeaders { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [System.IO.BinaryReader] $binaryReader, - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [System.IO.Stream] $stream, - [parameter(Position = 2, Mandatory = $true, ValueFromPipeline = $true)] - [uint16] $peFormat - ) - - $optionalHeaders = @{} - $optionalHeaders.PEFormat = $peFormat - $optionalHeaders.SubSystem = $null - $optionalHeaders.SubSystemMajor = $null - $optionalHeaders.SubSystemMinor = $null - $optionalHeaders.Characteristics = $null - $optionalHeaders.CLIHeader = $null - $optionalHeaders.Debug = $null - - # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L136 - Advance -stream $stream -count 44 - - # SubSysMajor 2 - # SubSystemMinor 2 - $optionalHeaders.SubSystemMajor = $binaryReader.ReadUInt16() - $optionalHeaders.SubSystemMinor = $binaryReader.ReadUInt16() - - Advance -stream $stream -count 18 - - # SubSystem 2 - $optionalHeaders.SubSystem = $binaryReader.ReadUInt16() - - # DLLFlags - $optionalHeaders.Characteristics = $binaryReader.ReadUInt16() - - # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L197 - if($peFormat -eq 0x20b) { - Advance -stream $stream -count 88 - } else { - Advance -stream $stream -count 72 - } - # Debug 8 - $optionalHeaders.Debug = ReadDataDirectory -binaryReader $binaryReader - - # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L209 - Advance -stream $stream -count 56 - - # CLIHeader - $optionalHeaders.CLIHeader = ReadDataDirectory -binaryReader $binaryReader - - # Reserved 8 - Advance -stream $stream -count 8 - - return New-Object -TypeName PSObject -Property $optionalHeaders - } - - # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/BinaryStreamReader.cs#L48 - function ReadSections { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [System.IO.BinaryReader] $binaryReader, - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [System.IO.Stream] $stream, - [parameter(Position = 2, Mandatory = $true, ValueFromPipeline = $true)] - [uint16] $count - ) - - # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L289 - function ReadSection { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [System.IO.Stream] $stream, - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [object] $section - ) - - # Save current position - $position = $stream.Position - - # Move to pointer - $stream.Position = $section.PointerToRawData - - # Reader pointer value - $length = [System.Convert]::ToInt32($section.SizeOfRawData) - $data = New-Object byte[] $length - $offset = 0 - $read = 0 - - while (($read = $stream.Read($data, $offset, $length - $offset)) -gt 0) { - $offset += $read - } - - $section.Data = $data - - # Restore old position - $stream.Position = $position - - return $section - - } - - $sections = New-Object object[] $count - - for($i = 0; $i -lt $count; $i++) { - - $section = @{} - - # Name - $section.Name = ReadZeroTerminatedString -binaryReader $reader -length 8 - - # Data - $section.Data = $null - - # VirtualSize 4 - Advance -stream $stream -count 4 - - # VirtualAddress 4 - $section.VirtualAddress = $binaryReader.ReadUInt32() - - # SizeOfRawData 4 - $section.SizeOfRawData = $binaryReader.ReadUInt32() - - # PointerToRawData 4 - $section.PointerToRawData = $binaryReader.ReadUInt32() - - # PointerToRelocations 4 - # PointerToLineNumbers 4 - # NumberOfRelocations 2 - # NumberOfLineNumbers 2 - # Characteristics 4 - Advance -stream $stream -count 16 - - # Read section data - $section = (ReadSection -stream $stream -section $section) - - # Add section - $sections[$i] = New-Object -TypeName PSObject -Property $section - - } - - return $sections - - } - - # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L307 - function ReadCLIHeader { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [System.IO.BinaryReader] $binaryReader, - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [System.IO.Stream] $stream, - [parameter(Position = 2, Mandatory = $true, ValueFromPipeline = $true)] - [object] $dataDirectory, - [parameter(Position = 3, Mandatory = $true, ValueFromPipeline = $true)] - [object] $sections - ) - - MoveTo -stream $stream -dataDirectory $dataDirectory -sections $sections - - # 4 because of major/minor - Advance -stream $stream -count 4 - - $cliHeader = @{} - $cliHeader.MajorRuntimeVersion = $binaryReader.ReadUInt16() - $cliHeader.MinorRuntimeVersion = $binaryReader.ReadUInt16() - $cliHeader.Metadata = ReadDataDirectory -binaryReader $binaryReader - $cliHeader.Attributes = $binaryReader.ReadUInt32() - $cliHeader.EntryPointToken = $binaryReader.ReadUInt32() - $cliHeader.Resources = ReadDataDirectory -binaryReader $binaryReader - $cliHeader.StrongName = ReadDataDirectory -binaryReader $binaryReader - - return New-Object -TypeName PSObject -Property $cliHeader - } - - # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L334 - function GetTargetFrameworkVersion { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [System.IO.BinaryReader] $binaryReader, - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [System.IO.Stream] $stream, - [parameter(Position = 2, Mandatory = $true, ValueFromPipeline = $true)] - [object] $dataDirectory, - [parameter(Position = 3, Mandatory = $true, ValueFromPipeline = $true)] - [object] $sections, - [parameter(Position = 4, Mandatory = $true, ValueFromPipeline = $true)] - [object] $optionalHeaders - ) - - - $targetFramework = "" - - MoveTo -stream $stream -dataDirectory $dataDirectory -sections $sections - - if($binaryReader.ReadUInt32() -ne 0x424a5342) { - Write-Error "BadImageFormat" - exit 1 - } - - # 4 because of major/minor - Advance -stream $stream -count 8 - - # Read framework version - $frameworkVersion = ReadZeroTerminatedString -binaryReader $binaryReader -length $binaryReader.ReadInt32() - - switch -Exact ($frameworkVersion[1]) { - 1 { - if($frameworkVersion[3] -eq 0) { - $targetFramework = "NET10" - } else { - $targetFramework = "NET11" - } - } - 2 { - $targetFramework = "NET20" - } - 4 { - if($optionalHeaders.SubSystemMinor -eq 0x6) { - $targetFramework = "NET45" - } else { - $targetFramework = "NET40" - } - } - } - - return $targetFramework - } - - # Read assembly - $stream = New-Object System.IO.FileStream($filename, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read) - $reader = New-Object System.IO.BinaryReader($stream) - $length = $stream.Length - - # Read PE format - # ============== - # The initial part here reads the PE format (not specific to .NET like cecil does) - # because we are interested in determining generic PE metadata - - # Read pointer to PE header. - $stream.Position = 0x3c - $peHeaderPtr = $reader.ReadUInt32() - if($peHeaderPtr -eq 0) { - $peHeaderPtr = 0x80 - } - - # Ensure there is at least enough room for the following structures: - # 24 byte PE Signature & Header - # 28 byte Standard Fields (24 bytes for PE32+) - # 68 byte NT Fields (88 bytes for PE32+) - # >= 128 byte Data Dictionary Table - if($peHeaderPtr > ($length - 256)) { - Write-Error "Invalid PE header" - exit 1 - } - - # Check the PE signature. Should equal 'PE\0\0'. - $stream.Position = $peHeaderPtr - $peSignature = $reader.ReadUInt32() - if ($peSignature -ne 0x00004550) { - Write-Error "Invalid PE signature" - exit 1 - } - - # Read PE header fields. - $machine = $reader.ReadUInt16() - $numberOfSections = $reader.ReadUInt16() - - Advance -stream $stream -count 14 - - $characteristics = $reader.ReadUInt16() - $peFormat = $reader.ReadUInt16() - - # Must be PE32 or PE32plus - if ($peFormat -ne 0x10b -and $peFormat -ne 0x20b) { - Write-Error "Invalid PE format. Must be either PE32 or PE32PLUS" - exit 1 - } - - $optionalHeaders = ReadOptionalHeaders -binaryReader $reader -stream $stream -peFormat $peFormat - if($optionalHeaders.CLIHeader.IsZero) { - return AssemblyInfo -peFormat $peFormat -characteristics $characteristics -machine $machine - } - - $sections = ReadSections -binaryReader $reader -stream $stream -count $numberOfSections - - $cliHeader = ReadCLIHeader -binaryReader $reader -stream $stream ` - -dataDirectory $optionalHeaders.CLIHeader -sections $sections - - $targetFramework = GetTargetFrameworkVersion -binaryReader $reader -stream $stream ` - -dataDirectory $cliHeader.Metadata -sections $sections -optionalHeaders $optionalHeaders - - $assemblyInfo = AssemblyInfo -peFormat $peFormat -attributes $cliHeader.Attributes -machine $machine -optionalHeaders $optionalHeaders ` - -characteristics $optionalHeaders.Characteristics -majorRuntimeVersion $cliHeader.MajorRuntimeVersion ` - -minorRuntimeVersion $cliHeader.MinorRuntimeVersion -targetFramework $targetFramework - - $reader.Dispose() - $stream.Dispose() - - return $assemblyInfo - -} - -function MyGet-Write-Diagnostic { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$message - ) - - Write-Host - Write-Host $message -ForegroundColor Green - Write-Host -} - -function MyGet-Die { - param( - [parameter(Position = 0, ValueFromPipeline = $true)] - [string]$message, - - [parameter(Position = 1, ValueFromPipeline = $true)] - [object[]]$output, - - [parameter(Position = 2, ValueFromPipeline = $true)] - [int]$exitCode = 1 - ) - - if ($output) { - Write-Output $output - $message += ". See output above." - } - - Write-Error "$message exitCode: $exitCode" - exit $exitCode - -} - -function MyGet-Create-Folder { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$folder - ) - - if(-not (Test-Path $folder)) { - New-Item -ItemType Directory -Path $folder - } - -} - -function MyGet-Grep { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$folder, - - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [string]$pattern, - - [parameter(Position = 2, ValueFromPipeline = $true)] - [bool]$recursive = $true - ) - - if($recursive) { - return Get-ChildItem $folder -Recurse | Where-Object { $_.FullName -match $pattern } - } - - return Get-ChildItem $folder | Where-Object { $_.FullName -match $pattern } -} - -function MyGet-EnvironmentVariable { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$name - ) - - return [Environment]::GetEnvironmentVariable($name) -} - -function MyGet-Set-EnvironmentVariable { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$name, - [parameter(Position = 1, ValueFromPipeline = $true)] - [string]$value - ) - - [Environment]::SetEnvironmentVariable($name, $value) -} - -function MyGet-BuildRunner { - - $buildRunner = MyGet-EnvironmentVariable "BuildRunner" - - if([String]::IsNullOrEmpty($buildRunner)) { - return "" - } - - return $buildRunner.tolower() - -} - -function MyGet-Package-Version { - param( - [string]$packageVersion = "" - ) - - $semverRegex = "^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?$" - - $buildRunner = MyGet-BuildRunner - if([String]::IsNullOrEmpty($buildRunner)) { - if(-not ($packageVersion -match $semverRegex)) { - Write-Error "Invalid package version input value" - } - return $packageVersion - } - - $envPackageVersion = MyGet-EnvironmentVariable "PackageVersion" - if([String]::IsNullOrEmpty($envPackageVersion)) { - return $packageVersion - } - - if(-not ($envPackageVersion -match $semverRegex)) { - Write-Error "Invalid package version value recieved from BuildRunner" - } - - return $envPackageVersion - -} - -function MyGet-CurlExe-Path { - param( - [ValidateSet("7.33.0", "latest")] - [string] $version = "latest" - ) - - $curl = Join-Path $buildRunnerToolsFolder "tools\curl\$version\curl.exe" - if (Test-Path $curl) { - return $curl - } - - MyGet-Die "Could not find curl executable: $curl" -} - -function MyGet-NugetExe-Path { - param( - [ValidateSet("2.5", "2.6", "2.7", "latest")] - [string] $version = "latest" - ) - - # Test environment variable - if((MyGet-BuildRunner -eq "myget") -and (Test-Path env:nuget)) { - return $env:nuget - } - - $nuget = Join-Path $buildRunnerToolsFolder "tools\nuget\$version\nuget.exe" - if (Test-Path $nuget) { - return $nuget - } - - MyGet-Die "Could not find nuget executable: $nuget" -} - -function MyGet-NunitExe-Path { - param( - [ValidateSet("2.6.2", "2.6.3", "latest")] - [string] $version = "latest" - ) - - $nunit = Join-Path $buildRunnerToolsFolder "tools\nunit\$version\nunit-console.exe" - if (Test-Path $nunit) { - return $nunit - } - MyGet-Die "Could not find nunit executable: $nunit" -} - -function MyGet-XunitExe-Path { - param( - [ValidateSet("1.9.2", "latest")] - [string] $version = "latest" - ) - - $xunit = Join-Path $buildRunnerToolsFolder "tools\xunit\$version\xunit.console.clr4.x86.exe" - if (Test-Path $xunit) { - return $xunit - } - - MyGet-Die "Could not find xunit executable" - -} - -function MyGet-Normalize-Path { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$path - ) - - return [System.IO.Path]::GetFullPath($path) -} - - -function MyGet-Normalize-Paths { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$basePath, - - [parameter(Position = 1, ValueFromPipeline = $true)] - [string[]]$paths = @() - ) - - if($paths -isnot [System.Array]) { - return @() - } - - $i = 0 - $paths | ForEach-Object { - $paths[$i] = [System.IO.Path]::Combine($basePath, $paths[$i]) - $i++; - } - - return $paths -} - -function MyGet-TargetFramework-To-Clr { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [ValidateSet("v2.0", "v3.5", "v4.0", "v4.5", "v4.5.1")] - [string]$targetFramework - ) - - $clr = $null - - switch -Exact ($targetFramework.ToLower()) { - "v2.0" { - $clr = "net20" - } - "v3.5" { - $clr = "net35" - } - "v4.0" { - $clr = "net40" - } - "v4.5" { - $clr = "net45" - } - "v4.5.1" { - $clr = "net451" - } - } - - return $clr -} - -function MyGet-Clr-To-TargetFramework { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [ValidateSet("net20", "net35", "net40", "net45", "net451")] - [string]$clr - ) - - $targetFramework = $null - - switch -Exact ($clr.ToLower()) { - "net20" { - $targetFramework = "v2.0" - } - "net35" { - $targetFramework = "v3.5" - } - "net40" { - $targetFramework = "v4.0" - } - "net45" { - $targetFramework = "v4.5" - } - "net451" { - $targetFramework = "v4.5.1" - } - } - - return $targetFramework -} - -# Build - -function MyGet-Build-Success { - - MyGet-Write-Diagnostic "Build: Success" - - exit 0 - -} - -function MyGet-Build-Clean { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$rootFolder, - [parameter(Position = 1, ValueFromPipeline=$true)] - [string]$folders = "bin,obj" - ) - - MyGet-Write-Diagnostic "Build: Clean" - - Get-ChildItem $rootFolder -Include $folders -Recurse | ForEach-Object { - Remove-Item $_.fullname -Force -Recurse - } - -} - -function MyGet-Build-Bootstrap { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$project - ) - - MyGet-Write-Diagnostic "Build: Bootstrap" - - $solutionFolder = [System.IO.Path]::GetDirectoryName($project) - $nugetExe = MyGet-NugetExe-Path - - . $nugetExe config -Set Verbosity=quiet - - if($project -match ".sln$") { - . $nugetExe restore $project -NonInteractive - } - - MyGet-Grep -folder $solutionFolder -recursive $true -pattern ".packages.config$" | ForEach-Object { - . $nugetExe restore $_.FullName -NonInteractive -SolutionDirectory $solutionFolder - } - -} - -function MyGet-Build-Nupkg { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$rootFolder, - - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [string]$outputFolder, - - [parameter(Position = 2, Mandatory = $true, ValueFromPipeline = $true)] - [ValidatePattern(".(sln|csproj)$")] - [string]$project, - - [parameter(Position = 3, Mandatory = $true, ValueFromPipeline = $true)] - [string]$config, - - [parameter(Position = 4, Mandatory = $true, ValueFromPipeline = $true)] - [ValidatePattern("^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?$")] - [string]$version, - - [parameter(Position = 5, Mandatory = $true, ValueFromPipeline = $true)] - [ValidateSet("x86", "x64", "AnyCpu")] - [string]$platform, - - [parameter(Position = 6, ValueFromPipeline = $true)] - [string]$nuspec = $null, - - [parameter(Position = 7, ValueFromPipeline = $true)] - [string]$nugetProperties = $null, - - # http://docs.nuget.org/docs/reference/command-line-reference#Pack_Command - [parameter(Position = 8, ValueFromPipeline = $true)] - [string]$nugetPackOptions = $null, - - [parameter(Position = 9, ValueFromPipeline = $true)] - [string]$nugetIncludeSymbols = $true - - ) - - if(-not (Test-Path $project)) { - MyGet-Die "Could not find project: $project" - } - - if($nuspec -eq "" -or (-not (Test-Path $nuspec))) { - $nuspec = [System.IO.Path]::Combine($rootFolder, $project) -ireplace ".(sln|csproj)$", ".nuspec" - } - - if(-not (Test-Path $nuspec)) { - MyGet-Die "Could not find nuspec: $nuspec" - } - - $rootFolder = MyGet-Normalize-Path $rootFolder - $outputFolder = MyGet-Normalize-Path $outputFolder - $nuspec = MyGet-Normalize-Path $nuspec - - $projectName = [System.IO.Path]::GetFileName($project) -ireplace ".(sln|csproj)$", "" - - # Nuget - $nugetCurrentFolder = [System.IO.Path]::GetDirectoryName($nuspec) - $nugetExe = MyGet-NugetExe-Path - $nugetProperties = @( - "Configuration=$config", - "Platform=$platform", - "OutputFolder=$outputFolder", - "NuspecFolder=$nugetCurrentFolder", - "$nugetProperties" - ) -join ";" - - MyGet-Write-Diagnostic "Nupkg: $projectName ($platform / $config)" - - if($nugetIncludeSymbols -eq $true) { - . $nugetExe pack $nuspec -OutputDirectory $outputFolder -Symbols -NonInteractive ` - -Properties "$nugetProperties" -Version $version "$nugetPackOptions" - } else { - . $nugetExe pack $nuspec -OutputDirectory $outputFolder -NonInteractive ` - -Properties "$nugetProperties" -Version $version "$nugetPackOptions" - } - - if($LASTEXITCODE -ne 0) { - MyGet-Die "Build failed: $projectName" -exitCode $LASTEXITCODE - } - - # Support multiple build runners - switch -Exact (MyGet-BuildRunner) { - "myget" { - - $mygetBuildFolder = Join-Path $rootFolder "Build" - - MyGet-Create-Folder $mygetBuildFolder - - MyGet-Grep $outputFolder -recursive $false -pattern ".nupkg$" | ForEach-Object { - $filename = $_.Name - $fullpath = $_.FullName - - cp $fullpath $mygetBuildFolder\$filename - } - - } - } - -} - -function MyGet-Build-Project { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$rootFolder, - - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [string]$outputFolder, - - [parameter(Position = 2, Mandatory = $true, ValueFromPipeline = $true)] - [ValidatePattern(".(sln|csproj)$")] - [string]$project, - - [parameter(Position = 3, Mandatory = $true, ValueFromPipeline = $true)] - [string]$config, - - [parameter(Position = 4, Mandatory = $true, ValueFromPipeline = $true)] - [ValidateSet("rebuild", "build")] - [string]$target, - - [parameter(Position = 5, Mandatory = $true, ValueFromPipeline = $true)] - [ValidatePattern("^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?$")] - [string]$version, - - [parameter(Position = 6, Mandatory = $false, ValueFromPipeline = $true)] - [ValidateSet("v1.1", "v2.0", "v3.5", "v4.0", "v4.5", "v4.5.1")] - [string[]]$targetFrameworks = @(), - - [parameter(Position = 7, Mandatory = $false, ValueFromPipeline = $true)] - [ValidateSet("v1.1", "v2.0", "v3.5", "v4.0", "v4.5", "v4.5.1")] - [string]$targetFramework = $null, - - [parameter(Position = 8, Mandatory = $true, ValueFromPipeline = $true)] - [ValidateSet("x86", "x64", "AnyCpu")] - [string]$platform, - - [parameter(Position = 9, Mandatory = $true, ValueFromPipeline = $true)] - [ValidateSet("Quiet", "Minimal", "Normal", "Detailed", "Diagnostic")] - [string]$verbosity = "Minimal", - - [parameter(Position = 10, ValueFromPipeline = $true)] - [string]$MSBuildCustomProperties = $null, - - [bool] $MSBuildx64 = $false - ) - - $projectOutputPath = Join-Path $outputFolder "$version\$platform\$config" - $projectPath = [System.IO.Path]::Combine($rootFolder, $project) - $projectName = [System.IO.Path]::GetFileName($projectPath) -ireplace ".(sln|csproj)$", "" - - MyGet-Create-Folder $outputFolder - - if(-Not (Test-Path $projectPath)) { - MyGet-Die "Could not find project: $projectPath" - } - - MyGet-Build-Bootstrap $projectPath - - if($targetFrameworks.Length -eq 0) { - $targetFrameworks += $targetFramework - } - - if($targetFrameworks.Length -eq 0) { - MyGet-Die "Please provide a targetframework to build project for." - } - - $targetFrameworks | ForEach-Object { - - $targetFramework = $_ - $buildOutputFolder = Join-Path $projectOutputPath "$targetFramework" - - MyGet-Create-Folder $buildOutputFolder - - MyGet-Write-Diagnostic "Build: $projectName ($platform / $config - $targetFramework)" - - # By default copy build output to final output path - $msbuildOutputFilename = Join-Path $buildOutputFolder "msbuild.log" - switch -Exact (MyGet-BuildRunner) { - "myget" { - - # Otherwise copy to root folder so that we can see the - # actual build failure in MyGet web interface - $msbuildOutputFilename = Join-Path $rootFolder "msbuild.log" - - } - } - - # YOLO - $msbuildPlatform = $platform - if($msbuildPlatform -eq "AnyCpu") { - $msbuildPlatform = "Any CPU" - } - - # Force x64 edition of msbuild - $MSBuildx64Framework = "" - if($MSBuildx64) { - $MSBuildx64Framework = "64" - } - - # http://msdn.microsoft.com/en-us/library/vstudio/ms164311.aspx - & "$(Get-Content env:windir)\Microsoft.NET\Framework$MSBuildx64Framework\v4.0.30319\MSBuild.exe" ` - $projectPath ` - /target:$target ` - /property:Configuration=$config ` - /property:OutputPath=$buildOutputFolder ` - /property:TargetFrameworkVersion=$targetFramework ` - /property:Platform=$msbuildPlatform ` - /maxcpucount ` - /verbosity:$verbosity ` - /fileLogger ` - /fileLoggerParameters:LogFile=$msbuildOutputFilename ` - /nodeReuse:false ` - /nologo ` - $MSBuildCustomProperties ` - - if($LASTEXITCODE -ne 0) { - MyGet-Die "Build failed: $projectName ($Config - $targetFramework)" -exitCode $LASTEXITCODE - } - - } - -} - -function MyGet-Build-Solution { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [ValidatePattern(".sln$")] - [string]$sln, - - [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [string]$rootFolder, - - [parameter(Position = 2, Mandatory = $true, ValueFromPipeline = $true)] - [string]$outputFolder, - - [parameter(Position = 3, Mandatory = $true, ValueFromPipeline = $true)] - [ValidatePattern("^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?$")] - [string]$version, - - [parameter(Position = 4, Mandatory = $true, ValueFromPipeline = $true)] - [string]$config, - - [parameter(Position = 5, Mandatory = $true, ValueFromPipeline = $true)] - [string]$target, - - [parameter(Position = 6, ValueFromPipeline = $true)] - [string[]]$projects = @(), - - [parameter(Position = 7, Mandatory = $true, ValueFromPipeline = $true)] - [string[]]$targetFrameworks, - - [parameter(Position = 8, Mandatory = $true, ValueFromPipeline = $true)] - [string[]]$platforms, - - [parameter(Position = 9, ValueFromPipeline = $true)] - [string]$verbosity = "Minimal", - - [parameter(Position = 10, ValueFromPipeline = $true)] - [string[]]$excludeNupkgProjects = @(), - - [parameter(Position = 11, ValueFromPipeline = $true)] - [string]$nuspec = $null, - - [parameter(Position = 12, ValueFromPipeline = $true)] - [string]$MSBuildCustomProperties = $null - ) - - if(-not (Test-Path $sln)) { - MyGet-Die "Could not find solution: $sln" - } - - $excludeNupkgProjects = MyGet-Normalize-Paths $rootFolder $excludeNupkgProjects - $projectName = [System.IO.Path]::GetFileName($sln) -ireplace ".sln$", "" - - # Building a solution - if($projects.Count -eq 0) { - $projects = @($sln) - # Building projects within a solution - } else { - $projects = MyGet-Normalize-Paths $rootFolder $projects - } - - $projects | ForEach-Object { - - $project = $_ - - $platforms | ForEach-Object { - - $platform = $_ - $finalBuildOutputFolder = Join-Path $outputFolder "$version\$platform\$config" - - MyGet-Build-Project -rootFolder $rootFolder -project $project -outputFolder $outputFolder ` - -target $target -config $config -targetFrameworks $targetFrameworks ` - -version $version -platform $platform -verbosity $verbosity ` - -MSBuildCustomProperties $MSBuildCustomProperties - - if(-not ($excludeNupkgProjects -contains $project)) { - MyGet-Build-Nupkg -rootFolder $rootFolder -project $project -nuspec $nuspec -outputFolder $finalBuildOutputFolder ` - -config $config -version $version -platform $platform - } - - } - - } -} - -# Nuget - -function MyGet-NuGet-Get-PackagesPath { - # https://github.com/github/Shimmer/blob/master/src/CreateReleasePackage/tools/utilities.psm1#L199 - param( - [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$folder - ) - - $cfg = Get-ChildItem -Path $folder -Filter nuget.config | Select-Object -first 1 - if($cfg) { - [xml]$config = Get-Content $cfg.FullName - $path = $config.configuration.config.add | ?{ $_.key -eq "repositorypath" } | select value - # Found nuget.config but it don't has repositorypath attribute - if($path) { - return $path.value.Replace("$", $folder) - } - } - - $parent = Split-Path $folder - - if(-not $parent) { - return $null - } - - return MyGet-NuGet-PackagesPath($parent) -} - -# Test runners - -function MyGet-TestRunner-Nunit { - # documentation: http://www.nunit.org/index.php?p=consoleCommandLine&r=2.6.3 - - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$rootFolder, - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$buildFolder, - [parameter(Position = 1, Mandatory = $false, ValueFromPipeline = $true)] - [string]$options = "/nologo", - [parameter(Position = 2, Mandatory = $false, ValueFromPipeline = $true)] - [string]$filter = "tests.*.dll$", - [parameter(Position = 3, Mandatory = $false, ValueFromPipeline = $true)] - [string]$minTargetFramework = "v2.0", - [parameter(Position = 4, Mandatory = $false, ValueFromPipeline = $true)] - [string]$version = "latest", - [parameter(Position = 5, Mandatory = $false, ValueFromPipeline = $true)] - [int16]$timeoutDuration = $([int16]::MaxValue) - ) - - $nunitExe = MyGet-NunitExe-Path - $nunitExeX86 = Join-Path (Split-Path -Parent $nunitExe) "nunit-console-x86.exe" - - # Filter test projects that has a older runtime that this value - $minTargetFramework = (MyGet-TargetFramework-To-Clr $minTargetFramework).Substring(3) - - # 4.5.1 -> 4.5 - if($minTargetFramework -eq "451") { - $minTargetFramework = "45" - } - - # AnyCpu, X64 - $net20 = @() - $net40 = @() - $net45 = @() - - # X86 - $net20X86 = @() - $net40X86 = @() - $net45X86 = @() - - # Find all test libraries based on specified filter - Get-ChildItem $buildFolder -Recurse | Where-Object { $_.FullName -match $filter } | ForEach-Object { - $fullPath = $_.FullName - $assemblyInfo = MyGet-AssemblyInfo $fullPath - # Only accept managed libraries - if($assemblyInfo.ModuleAttributes -contains "ILOnly") { - $targetFramework = $assemblyInfo.TargetFramework.Substring(3) - if (-not ($targetFramework -ge $minTargetFramework)) { - return - } - if($assemblyInfo.ProcessorArchitecture -eq "AnyCpu") { - if($targetFramework -eq "20") { - $net20X86 += $fullPath - } elseif($targetFramework -eq "40") { - $net40X86 += $fullPath - } else { - $net45X86 += $fullPath - } - } else { - if($targetFramework -eq "20") { - $net20 += $fullPath - } elseif($targetFramework -eq "40") { - $net40 += $fullPath - } else { - $net45 += $fullPath - } - } - } else { - Write-Output "Skipped test library $fullPath because it's not .NET assembly" - } - - } - - function TestSuite($nunit, $arguments) { - - $process = Start-Process -PassThru -NoNewWindow $nunit ($arguments | %{ "`"$_`"" }) - Wait-Process -InputObject $process -Timeout $timeoutDuration - - $exitCode = $process.ExitCode - if($exitCode -ne 0) { - MyGet-Die "Test suite failed" -exitCode $exitCode - } - - } - - # AnyCpu, X64 - $minClrRuntime = $null - if($net45 -ne 0) { - $minClrRuntime = "net-4.5" - } elseif($net40 -ne 0) { - $minClrRuntime = "net-4.0" - } elseif($net20 -ne 0) { - $minClrRuntime = "net-2.0" - } - - if($minClrRuntime -ne $null) { - - $arguments = @() - $net20 | ForEach-Object { $arguments += $_ } - $net40 | ForEach-Object { $arguments += $_ } - $net45 | ForEach-Object { $arguments += $_ } - - $numProjects = $arguments.Length - - MyGet-Write-Diagnostic "nunit-console.exe: Running tests for $numProjects projects." - - Write-Output "" - Write-Output $arguments | Sort-Object -Property FullName - Write-Output "" - - $xml = Join-Path $buildFolder "nunit-result.xml" - $arguments += ($options -split " ") - $arguments += "/framework=$minClrRuntime" - $arguments += "/xml=$xml" - - TestSuite -nunit $nunitExe -arguments $arguments - } - - # X86 - $minClrRuntimeX86 = $null - if($net45X86 -ne 0) { - $minClrRuntimeX86 = "net-4.5" - } elseif($net40X86 -ne 0) { - $minClrRuntimeX86 = "net-4.0" - } elseif($net20X86 -ne 0) { - $minClrRuntimeX86 = "net-2.0" - } - - if($minClrRuntimeX86 -ne $null) { - - $arguments = @() - $net20X86 | ForEach-Object { $arguments += $_ } - $net40X86 | ForEach-Object { $arguments += $_ } - $net45X86 | ForEach-Object { $arguments += $_ } - - $numProjects = $arguments.Length - - MyGet-Write-Diagnostic "nunit-console-x86.exe: Running tests for $numProjects projects." - - Write-Output "" - Write-Output $arguments | Sort-Object -Property FullName - Write-Output "" - - $xml = Join-Path $buildFolder "nunit-result-x86.xml" - $arguments += ($options -split " ") - $arguments += "/framework=$minClrRuntimeX86" - $arguments += "/xml=$xml" - - TestSuite -nunit $nunitExeX86 -arguments $arguments - } - -} - -function MyGet-TestRunner-Xunit { - param( - [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string[]]$projects - ) - - # see: https://github.com/github/Shimmer/blob/bfda6f3e13ab962ad63d81c661d43208070593e8/script/Run-UnitTests.ps1#L5 - - MyGet-Die "Not implemented. Please contribute a PR @ https://www.github/peters/myget" -} - -# Squirrel - -function MyGet-Squirrel-New-Release { - param( - [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string]$solutionFolder, - [Parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [string]$buildFolder - ) - - $packagesDir = Join-Path $solutionFolder "packages" - - $commandsPsm1 = MyGet-Grep -folder $packagesDir -recursive $true ` - -pattern "Shimmer.*commands.psm1$" | - Sort-Object FullName -Descending | - Select-Object -first 1 - - if(-not (Test-Path $commandsPsm1.FullName)) { - MyGet-Die "Could not find any Squirrel nupkg's containing commands.psm1" - } - - MyGet-Write-Diagnostic "Squirrel: Creating new release" - - Import-Module $commandsPsm1.FullName - - New-ReleaseForPackage -SolutionDir $solutionFolder -BuildDir $buildFolder - -} - -# Curl - -function MyGet-Curl-Upload-File { - param( - [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [ValidateSet("scp", "sftp")] - [string]$protocol, - [Parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)] - [string]$usernameAndHost, - [Parameter(Position = 2, Mandatory = $false, ValueFromPipeline = $true)] - [string]$privateKey, - [Parameter(Position = 3, Mandatory = $false, ValueFromPipeline = $true)] - [string]$publicKey, - [Parameter(Position = 4, Mandatory = $false, ValueFromPipeline = $true)] - [string]$filename, - [Parameter(Position = 4, Mandatory = $false, ValueFromPipeline = $true)] - [string[]]$filenames = @(), - [Parameter(Position = 5, Mandatory = $true, ValueFromPipeline = $true)] - [string]$destination, - [Parameter(Position = 6, Mandatory = $false, ValueFromPipeline = $true)] - [string]$curlOptions = "" - ) - - # Default *UNIX values - - if($privateKey -eq "" -and $publicKey -eq "") { - $privateKey = "id_rsa" - $publicKey = "id_rsa.pub" - } - - # Default to C:\Users\USERNAME\.ssh - - if(-not (Test-Path $privateKey) -and (-not [System.IO.Path]::IsPathRooted($privateKey))) { - $privateKey = Join-Path $env:HOMEDRIVE $env:HOMEPATH\.ssh\$privateKey - } - - if(-not (Test-Path $publicKey) -and (-not [System.IO.Path]::IsPathRooted($publicKey))) { - $publicKey = Join-Path $env:HOMEDRIVE $env:HOMEPATH\.ssh\$publicKey - } - - # Verify that keys exist - - if(-not (Test-Path $privateKey)) { - MyGet-Die "Curl: File does not exist: $privateKey" - } - - if(-not (Test-Path $publicKey)) { - MyGet-Die "Curl: File does not exist: $publicKey" - } - - # Single file upload - if($filenames.Length -eq 0) { - if($filename -eq "") { - MyGet-Die "Curl: Invalid filename (empty string)" - } - $filenames += $filename - } - - if($filenames.Length -eq 0) { - MyGet-Die "Curl: Please specify a file to upload" - } - - # Estimate upload size - $estimatedSize = 0 - $filenames | ForEach-Object { - $position = [array]::IndexOf($filenames, $_) - if($_ -eq "") { - MyGet-Die ("Curl: Invalid filename (empty string at position {0})" -f ($position)) - } - if(-not (Test-Path -Path $_ -PathType Leaf)) { - MyGet-Die ("Curl: File does note exist: {0} (position {1})" -f ($_, $position)) - } - $estimatedSize += (Get-Item $_).Length - } - - switch($estimatedSize) { - { $_ -gt 1tb } - { $estimatedSize = "{0:n2} TB" -f ($_ / 1tb) } - { $_ -gt 1gb } - { $estimatedSize = "{0:n2} GB" -f ($_ / 1gb) } - { $_ -gt 1mb } - { $estimatedSize = "{0:n2} MB" -f ($_ / 1mb) } - { $_ -gt 1kb } - { $estimatedSize = "{0:n2} KB" -f ($_ / 1Kb) } - default - { $estimatedSize = "{0} B" -f $_ } - } - - $plural = if($filenames.Length -gt 1) { "s" } else { "" } - MyGet-Write-Diagnostic("Curl: Uploading {0} file{1} ({2})" -f ($filenames.Length, $plural, $estimatedSize)) - - # Remote destination - $remoteDestination = $protocol - $remoteDestination += "://" - $remoteDestination += $usernameAndHost - $remoteDestination += ":" - $remoteDestination += $destination - - $filenames | ForEach-Object { - $filename = $_ - $filenameRemote = Split-Path -Leaf $filename - - Write-Output "" - Write-Output $filename - Write-Output "" - - . (MyGet-CurlExe-Path) $curlOptions --insecure --upload-file $filename ` - --key $privateKey --pubkey $publicKey $remoteDestination/$filenameRemote - - if($LASTEXITCODE -ne 0) { - MyGet-Die("Curl: Upload failed {0}" -f (Split-Path -Leaf $filename)) - } - - } - -} - -## Self updating - -if(-not (Test-Path $buildRunnerToolsFolder)) { - - MyGet-Write-Diagnostic "Downloading prerequisites" - - git clone --depth=1 https://github.com/myget/BuildTools.git $buildRunnerToolsFolder - - $(Get-Item $buildRunnerToolsFolder).Attributes = "Hidden" - -} - -if($updateSelf -eq $true) { - - MyGet-Write-Diagnostic "Updating build tools" - - $rootFolder = Split-Path $MyInvocation.MyCommand.Path - - Set-Location $buildRunnerToolsFolder - git pull origin master - Set-Location $rootFolder - - MyGet-Write-Diagnostic "Updating myget.include" - - Invoke-WebRequest "https://raw.github.com/peters/myget/master/myget.include.ps1" -OutFile $rootFolder\myget.include.ps1 -Verbose - - Remove-Variable -Name rootFolder - -} \ No newline at end of file diff --git a/semver.ps1 b/semver.ps1 deleted file mode 100644 index 13a0942..0000000 --- a/semver.ps1 +++ /dev/null @@ -1,39 +0,0 @@ -param( - [string]$packageVersion = $null, - [string]$config = "Release", - [string]$target = "Rebuild", - [string]$verbosity = "Minimal" -) - -$rootFolder = Split-Path -parent $script:MyInvocation.MyCommand.Path -. $rootFolder\myget.include.ps1 - -$packageVersion = MyGet-Package-Version $packageVersion - -$project = "semver\semver.csproj" -$platform = "AnyCPU" -$targetFrameworks = @("v2.0","v3.5","v4.0","v4.5","v4.5.1") - -$projectName = [System.IO.Path]::GetFileName($project) -ireplace ".(sln|csproj)$", "" -$outputFolder = Join-Path $rootFolder "bin\$projectName" -$buildOutputPath = Join-Path $outputFolder "$packageVersion\$platform\$config" - -MyGet-AssemblyVersion-Set -projectFolder $project -version $packageVersion - -MyGet-Build-Project -rootFolder $rootFolder ` - -outputFolder $outputFolder ` - -project $project ` - -config $config ` - -target $target ` - -targetFrameworks $targetFrameworks ` - -platform $platform ` - -verbosity $verbosity ` - -version $packageVersion ` - -MyGet-Build-Nupkg -rootFolder $rootFolder ` - -outputFolder $buildOutputPath ` - -project $project ` - -config $config ` - -version $packageVersion ` - -platform $platform ` - -nugetIncludeSymbols $false \ No newline at end of file diff --git a/Semver/Properties/AssemblyInfo.cs b/src/Semver/Properties/AssemblyInfo.cs similarity index 74% rename from Semver/Properties/AssemblyInfo.cs rename to src/Semver/Properties/AssemblyInfo.cs index adbc1ea..b60777f 100644 --- a/Semver/Properties/AssemblyInfo.cs +++ b/src/Semver/Properties/AssemblyInfo.cs @@ -7,6 +7,7 @@ [assembly: AssemblyCopyright("Copyright © 2013 Max Hauser")] [assembly: ComVisible(false)] [assembly: Guid("e208ca67-5b59-45d9-a29a-7f30137d3beb")] -[assembly: AssemblyVersion("1.1.2")] -[assembly: AssemblyFileVersion("1.1.2")] -[assembly: AssemblyInformationalVersion("1.1.2")] + +[assembly: AssemblyVersion("2.0.0")] +[assembly: AssemblyFileVersion("2.0.0")] +[assembly: AssemblyInformationalVersion("2.0.0")] \ No newline at end of file diff --git a/Semver/SemVersion.cs b/src/Semver/SemVersion.cs similarity index 92% rename from Semver/SemVersion.cs rename to src/Semver/SemVersion.cs index c3b62a2..1d9aab6 100644 --- a/Semver/SemVersion.cs +++ b/src/Semver/SemVersion.cs @@ -1,504 +1,537 @@ -using System; -using System.Globalization; -using System.Runtime.Serialization; -using System.Security.Permissions; -using System.Text.RegularExpressions; - -namespace Semver -{ - /// - /// A semantic version implementation. - /// Conforms to v2.0.0 of http://semver.org/ - /// - [Serializable] - public sealed class SemVersion : IComparable, IComparable, ISerializable - { - static Regex parseEx = - new Regex(@"^(?\d+)" + - @"(\.(?\d+))?" + - @"(\.(?\d+))?" + - @"(\-(?
[0-9A-Za-z\-\.]+))?" +
-                @"(\+(?[0-9A-Za-z\-\.]+))?$",
-                RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
-
-        /// 
-        /// Initializes a new instance of the  class.
-        /// 
-        /// 
-        /// 
-        /// 
-        private SemVersion(SerializationInfo info, StreamingContext context)
-        {
-            if (info == null) throw new ArgumentNullException("info");
-            var semVersion = Parse(info.GetString("SemVersion"));
-            Major = semVersion.Major;
-            Minor = semVersion.Minor;
-            Patch = semVersion.Patch;
-            Prerelease = semVersion.Prerelease;
-            Build = semVersion.Build;
-        }
-
-        /// 
-        /// Initializes a new instance of the  class.
-        /// 
-        /// The major version.
-        /// The minor version.
-        /// The patch version.
-        /// The prerelease version (eg. "alpha").
-        /// The build eg ("nightly.232").
-        public SemVersion(int major, int minor = 0, int patch = 0, string prerelease = "", string build = "")
-        {
-            this.Major = major;
-            this.Minor = minor;
-            this.Patch = patch;
-
-            // strings are interned to be able to compare by reference in equals method
-            this.Prerelease = String.Intern(prerelease ?? "");
-            this.Build = String.Intern(build ?? "");
-        }
-
-        /// 
-        /// Initializes a new instance of the  class.
-        /// 
-        /// The  that is used to initialize 
-        /// the Major, Minor, Patch and Build properties.
-        public SemVersion(Version version)
-        {
-            version = version ?? new Version();
-
-            this.Major = version.Major;
-            this.Minor = version.Minor;
-
-            if (version.Revision >= 0)
-            {
-                this.Patch = version.Revision;
-            }
-
-            this.Prerelease = String.Intern("");
-
-            if (version.Build > 0)
-            {
-                this.Build = String.Intern(version.Build.ToString());
-            }
-            else
-            {
-                this.Build = String.Intern("");
-            }
-        }
-
-        /// 
-        /// Parses the specified string to a semantic version.
-        /// 
-        /// The version string.
-        /// If set to true minor and patch version are required, else they default to 0.
-        /// The SemVersion object.
-        /// When a invalid version string is passed.
-        public static SemVersion Parse(string version, bool strict = false)
-        {
-            var match = parseEx.Match(version);
-            if (!match.Success)
-                throw new ArgumentException("Invalid version.", "version");
-
-            var major = Int32.Parse(match.Groups["major"].Value, CultureInfo.InvariantCulture);
-
-            var minorMatch = match.Groups["minor"];
-            int minor = 0;
-            if (minorMatch.Success)
-                minor = Int32.Parse(minorMatch.Value, CultureInfo.InvariantCulture);
-            else if (strict)
-                throw new InvalidOperationException("Invalid version (no minor version given in strict mode)");
-
-            var patchMatch = match.Groups["patch"];
-            int patch = 0;
-            if (patchMatch.Success)
-                patch = Int32.Parse(patchMatch.Value, CultureInfo.InvariantCulture);
-            else if (strict)
-                throw new InvalidOperationException("Invalid version (no patch version given in strict mode)");
-
-            var prerelease = match.Groups["pre"].Value;
-            var build = match.Groups["build"].Value;
-
-            return new SemVersion(major, minor, patch, prerelease, build);
-        }
-
-        /// 
-        /// Parses the specified string to a semantic version.
-        /// 
-        /// The version string.
-        /// When the method returns, contains a SemVersion instance equivalent 
-        /// to the version string passed in, if the version string was valid, or null if the 
-        /// version string was not valid.
-        /// If set to true minor and patch version are required, else they default to 0.
-        /// False when a invalid version string is passed, otherwise true.
-        public static bool TryParse(string version, out SemVersion semver, bool strict = false)
-        {
-            try
-            {
-                semver = Parse(version, strict);
-                return true;
-            }
-            catch (Exception)
-            {
-                semver = null;
-                return false;
-            }
-        }
-
-        /// 
-        /// Tests the specified versions for equality.
-        /// 
-        /// The first version.
-        /// The second version.
-        /// If versionA is equal to versionB true, else false.
-        public static bool Equals(SemVersion versionA, SemVersion versionB)
-        {
-            if (ReferenceEquals(versionA, null))
-                return ReferenceEquals(versionB, null);
-            return versionA.Equals(versionB);
-        }
-
-        /// 
-        /// Compares the specified versions.
-        /// 
-        /// The version to compare to.
-        /// The version to compare against.
-        /// If versionA < versionB < 0, if versionA > versionB > 0,
-        /// if versionA is equal to versionB 0.
-        public static int Compare(SemVersion versionA, SemVersion versionB)
-        {
-            if (ReferenceEquals(versionA, null))
-                return ReferenceEquals(versionB, null) ? 0 : -1;
-            return versionA.CompareTo(versionB);
-        }
-
-        /// 
-        /// Make a copy of the current instance with optional altered fields. 
-        /// 
-        /// The major version.
-        /// The minor version.
-        /// The patch version.
-        /// The prerelease text.
-        /// The build text.
-        /// The new version object.
-        public SemVersion Change(int? major = null, int? minor = null, int? patch = null,
-            string prerelease = null, string build = null)
-        {
-            return new SemVersion(
-                major ?? this.Major,
-                minor ?? this.Minor,
-                patch ?? this.Patch,
-                prerelease ?? this.Prerelease,
-                build ?? this.Build);
-        }
-
-        /// 
-        /// Gets the major version.
-        /// 
-        /// 
-        /// The major version.
-        /// 
-        public int Major { get; private set; }
-
-        /// 
-        /// Gets the minor version.
-        /// 
-        /// 
-        /// The minor version.
-        /// 
-        public int Minor { get; private set; }
-
-        /// 
-        /// Gets the patch version.
-        /// 
-        /// 
-        /// The patch version.
-        /// 
-        public int Patch { get; private set; }
-
-        /// 
-        /// Gets the pre-release version.
-        /// 
-        /// 
-        /// The pre-release version.
-        /// 
-        public string Prerelease { get; private set; }
-
-        /// 
-        /// Gets the build version.
-        /// 
-        /// 
-        /// The build version.
-        /// 
-        public string Build { get; private set; }
-
-        /// 
-        /// Returns a  that represents this instance.
-        /// 
-        /// 
-        /// A  that represents this instance.
-        /// 
-        public override string ToString()
-        {
-            var version = "" + Major + "." + Minor + "." + Patch;
-            if (!String.IsNullOrEmpty(Prerelease))
-                version += "-" + Prerelease;
-            if (!String.IsNullOrEmpty(Build))
-                version += "+" + Build;
-            return version;
-        }
-
-        /// 
-        /// Compares the current instance with another object of the same type and returns an integer that indicates 
-        /// whether the current instance precedes, follows, or occurs in the same position in the sort order as the 
-        /// other object.
-        /// 
-        /// An object to compare with this instance.
-        /// 
-        /// A value that indicates the relative order of the objects being compared. 
-        /// The return value has these meanings: Value Meaning Less than zero 
-        ///  This instance precedes  in the sort order. 
-        ///  Zero This instance occurs in the same position in the sort order as . i
-        ///  Greater than zero This instance follows  in the sort order.
-        /// 
-        public int CompareTo(object obj)
-        {
-            return CompareTo((SemVersion)obj);
-        }
-
-        /// 
-        /// Compares the current instance with another object of the same type and returns an integer that indicates 
-        /// whether the current instance precedes, follows, or occurs in the same position in the sort order as the 
-        /// other object.
-        /// 
-        /// An object to compare with this instance.
-        /// 
-        /// A value that indicates the relative order of the objects being compared. 
-        /// The return value has these meanings: Value Meaning Less than zero 
-        ///  This instance precedes  in the sort order. 
-        ///  Zero This instance occurs in the same position in the sort order as . i
-        ///  Greater than zero This instance follows  in the sort order.
-        /// 
-        public int CompareTo(SemVersion other)
-        {
-            if (ReferenceEquals(other, null))
-                return 1;
-
-            var r = this.CompareByPrecedence(other);
-            if (r != 0)
-                return r;
-
-            r = CompareComponent(this.Build, other.Build);
-            return r;
-        }
-
-        /// 
-        /// Compares to semantic versions by precedence. This does the same as a Equals, but ignores the build information.
-        /// 
-        /// The semantic version.
-        /// true if the version precedence matches.
-        public bool PrecedenceMatches(SemVersion other)
-        {
-            return CompareByPrecedence(other) == 0;
-        }
-
-        /// 
-        /// Compares to semantic versions by precedence. This does the same as a Equals, but ignores the build information.
-        /// 
-        /// The semantic version.
-        /// 
-        /// A value that indicates the relative order of the objects being compared. 
-        /// The return value has these meanings: Value Meaning Less than zero 
-        ///  This instance precedes  in the version precedence.
-        ///  Zero This instance has the same precedence as . i
-        ///  Greater than zero This instance has creater precedence as .
-        /// 
-        public int CompareByPrecedence(SemVersion other)
-        {
-            if (ReferenceEquals(other, null))
-                return 1;
-
-            var r = this.Major.CompareTo(other.Major);
-            if (r != 0) return r;
-
-            r = this.Minor.CompareTo(other.Minor);
-            if (r != 0) return r;
-
-            r = this.Patch.CompareTo(other.Patch);
-            if (r != 0) return r;
-
-            r = CompareComponent(this.Prerelease, other.Prerelease, true);
-            return r;
-        }
-
-        static int CompareComponent(string a, string b, bool lower = false)
-        {
-            var aEmpty = String.IsNullOrEmpty(a);
-            var bEmpty = String.IsNullOrEmpty(b);
-            if (aEmpty && bEmpty)
-                return 0;
-
-            if (aEmpty)
-                return lower ? 1 : -1;
-            if (bEmpty)
-                return lower ? -1 : 1;
-
-            var aComps = a.Split('.');
-            var bComps = b.Split('.');
-
-            var minLen = Math.Min(aComps.Length, bComps.Length);
-            for (int i = 0; i < minLen; i++)
-            {
-                var ac = aComps[i];
-                var bc = bComps[i];
-                int anum, bnum;
-                var isanum = Int32.TryParse(ac, out anum);
-                var isbnum = Int32.TryParse(bc, out bnum);
-                int r;
-                if (isanum && isbnum)
-                {
-                    r = anum.CompareTo(bnum);
-                    if (r != 0) return anum.CompareTo(bnum);
-                }
-                else
-                {
-                    if (isanum)
-                        return -1;
-                    if (isbnum)
-                        return 1;
-                    r = String.CompareOrdinal(ac, bc);
-                    if (r != 0)
-                        return r;
-                }
-            }
-
-            return aComps.Length.CompareTo(bComps.Length);
-        }
-
-        /// 
-        /// Determines whether the specified  is equal to this instance.
-        /// 
-        /// The  to compare with this instance.
-        /// 
-        ///   true if the specified  is equal to this instance; otherwise, false.
-        /// 
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(obj, null))
-                return false;
-
-            if (ReferenceEquals(this, obj))
-                return true;
-
-            var other = (SemVersion)obj;
-
-            // do string comparison by reference (possible because strings are interned in ctor)
-            return this.Major == other.Major &&
-                this.Minor == other.Minor &&
-                this.Patch == other.Patch &&
-                ReferenceEquals(this.Prerelease, other.Prerelease) &&
-                ReferenceEquals(this.Build, other.Build);
-        }
-
-        /// 
-        /// Returns a hash code for this instance.
-        /// 
-        /// 
-        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
-        /// 
-        public override int GetHashCode()
-        {
-            unchecked
-            {
-                int result = this.Major.GetHashCode();
-                result = result * 31 + this.Minor.GetHashCode();
-                result = result * 31 + this.Patch.GetHashCode();
-                result = result * 31 + this.Prerelease.GetHashCode();
-                result = result * 31 + this.Build.GetHashCode();
-                return result;
-            }
-        }
-
-        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
-        public void GetObjectData(SerializationInfo info, StreamingContext context)
-        {
-            if (info == null) throw new ArgumentNullException("info");
-            info.AddValue("SemVersion", ToString());
-        }
-
-        /// 
-        /// Implicit conversion from string to SemVersion.
-        /// 
-        /// The semantic version.
-        /// The SemVersion object.
-        public static implicit operator SemVersion(string version)
-        {
-            return SemVersion.Parse(version);
-        }
-
-        /// 
-        /// The override of the equals operator. 
-        /// 
-        /// The left value.
-        /// The right value.
-        /// If left is equal to right true, else false.
-        public static bool operator ==(SemVersion left, SemVersion right)
-        {
-            return SemVersion.Equals(left, right);
-        }
-
-        /// 
-        /// The override of the un-equal operator. 
-        /// 
-        /// The left value.
-        /// The right value.
-        /// If left is not equal to right true, else false.
-        public static bool operator !=(SemVersion left, SemVersion right)
-        {
-            return !SemVersion.Equals(left, right);
-        }
-
-        /// 
-        /// The override of the greater operator. 
-        /// 
-        /// The left value.
-        /// The right value.
-        /// If left is greater than right true, else false.
-        public static bool operator >(SemVersion left, SemVersion right)
-        {
-            return SemVersion.Compare(left, right) > 0;
-        }
-
-        /// 
-        /// The override of the greater than or equal operator. 
-        /// 
-        /// The left value.
-        /// The right value.
-        /// If left is greater than or equal to right true, else false.
-        public static bool operator >=(SemVersion left, SemVersion right)
-        {
-            return left == right || left > right;
-        }
-
-        /// 
-        /// The override of the less operator. 
-        /// 
-        /// The left value.
-        /// The right value.
-        /// If left is less than right true, else false.
-        public static bool operator <(SemVersion left, SemVersion right)
-        {
-            return SemVersion.Compare(left, right) < 0;
-        }
-
-        /// 
-        /// The override of the less than or equal operator. 
-        /// 
-        /// The left value.
-        /// The right value.
-        /// If left is less than or equal to right true, else false.
-        public static bool operator <=(SemVersion left, SemVersion right)
-        {
-            return left == right || left < right;
-        }
-    }
-}
+using System;
+#if !NETSTANDARD
+using System.Globalization;
+using System.Runtime.Serialization;
+using System.Security.Permissions;
+#endif
+using System.Text.RegularExpressions;
+
+namespace Semver
+{
+    /// 
+    /// A semantic version implementation.
+    /// Conforms to v2.0.0 of http://semver.org/
+    /// 
+#if NETSTANDARD
+    public sealed class SemVersion : IComparable, IComparable
+#else
+    [Serializable]
+    public sealed class SemVersion : IComparable, IComparable, ISerializable
+#endif
+    {
+        static Regex parseEx =
+            new Regex(@"^(?\d+)" +
+                @"(\.(?\d+))?" +
+                @"(\.(?\d+))?" +
+                @"(\-(?
[0-9A-Za-z\-\.]+))?" +
+                @"(\+(?[0-9A-Za-z\-\.]+))?$",
+#if NETSTANDARD
+                RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture);
+#else
+                RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
+#endif
+
+#if !NETSTANDARD
+        /// 
+        /// Initializes a new instance of the  class.
+        /// 
+        /// 
+        /// 
+        /// 
+        private SemVersion(SerializationInfo info, StreamingContext context)
+        {
+            if (info == null) throw new ArgumentNullException("info");
+            var semVersion = Parse(info.GetString("SemVersion"));
+            Major = semVersion.Major;
+            Minor = semVersion.Minor;
+            Patch = semVersion.Patch;
+            Prerelease = semVersion.Prerelease;
+            Build = semVersion.Build;
+        }
+#endif
+
+        /// 
+        /// Initializes a new instance of the  class.
+        /// 
+        /// The major version.
+        /// The minor version.
+        /// The patch version.
+        /// The prerelease version (eg. "alpha").
+        /// The build eg ("nightly.232").
+        public SemVersion(int major, int minor = 0, int patch = 0, string prerelease = "", string build = "")
+        {
+            this.Major = major;
+            this.Minor = minor;
+            this.Patch = patch;
+
+            this.Prerelease = prerelease ?? "";
+            this.Build = build ?? "";
+        }
+
+        /// 
+        /// Initializes a new instance of the  class.
+        /// 
+        /// The  that is used to initialize 
+        /// the Major, Minor, Patch and Build properties.
+        public SemVersion(Version version)
+        {
+            if (version == null)
+                throw new ArgumentNullException("version");
+
+            this.Major = version.Major;
+            this.Minor = version.Minor;
+
+            if (version.Revision >= 0)
+            {
+                this.Patch = version.Revision;
+            }
+
+            this.Prerelease = String.Empty;
+
+            if (version.Build > 0)
+            {
+                this.Build = version.Build.ToString();
+            }
+            else
+            {
+                this.Build = String.Empty;
+            }
+        }
+
+        /// 
+        /// Parses the specified string to a semantic version.
+        /// 
+        /// The version string.
+        /// If set to true minor and patch version are required, else they default to 0.
+        /// The SemVersion object.
+        /// When a invalid version string is passed.
+        public static SemVersion Parse(string version, bool strict = false)
+        {
+            var match = parseEx.Match(version);
+            if (!match.Success)
+                throw new ArgumentException("Invalid version.", "version");
+
+#if NETSTANDARD
+            var major = int.Parse(match.Groups["major"].Value);
+#else
+            var major = int.Parse(match.Groups["major"].Value, CultureInfo.InvariantCulture);
+#endif
+
+            var minorMatch = match.Groups["minor"];
+            int minor = 0;
+            if (minorMatch.Success) 
+            {
+#if NETSTANDARD
+                minor = int.Parse(minorMatch.Value);
+#else
+                minor = int.Parse(minorMatch.Value, CultureInfo.InvariantCulture);
+#endif
+            }
+            else if (strict)
+            {
+                throw new InvalidOperationException("Invalid version (no minor version given in strict mode)");
+            }
+
+            var patchMatch = match.Groups["patch"];
+            int patch = 0;
+            if (patchMatch.Success)
+            {
+#if NETSTANDARD
+                patch = int.Parse(patchMatch.Value);
+#else
+                patch = int.Parse(patchMatch.Value, CultureInfo.InvariantCulture);
+#endif
+            }
+            else if (strict) 
+            {
+                throw new InvalidOperationException("Invalid version (no patch version given in strict mode)");
+            }
+
+            var prerelease = match.Groups["pre"].Value;
+            var build = match.Groups["build"].Value;
+
+            return new SemVersion(major, minor, patch, prerelease, build);
+        }
+
+        /// 
+        /// Parses the specified string to a semantic version.
+        /// 
+        /// The version string.
+        /// When the method returns, contains a SemVersion instance equivalent 
+        /// to the version string passed in, if the version string was valid, or null if the 
+        /// version string was not valid.
+        /// If set to true minor and patch version are required, else they default to 0.
+        /// False when a invalid version string is passed, otherwise true.
+        public static bool TryParse(string version, out SemVersion semver, bool strict = false)
+        {
+            try
+            {
+                semver = Parse(version, strict);
+                return true;
+            }
+            catch (Exception)
+            {
+                semver = null;
+                return false;
+            }
+        }
+
+        /// 
+        /// Tests the specified versions for equality.
+        /// 
+        /// The first version.
+        /// The second version.
+        /// If versionA is equal to versionB true, else false.
+        public static bool Equals(SemVersion versionA, SemVersion versionB)
+        {
+            if (ReferenceEquals(versionA, null))
+                return ReferenceEquals(versionB, null);
+            return versionA.Equals(versionB);
+        }
+
+        /// 
+        /// Compares the specified versions.
+        /// 
+        /// The version to compare to.
+        /// The version to compare against.
+        /// If versionA < versionB < 0, if versionA > versionB > 0,
+        /// if versionA is equal to versionB 0.
+        public static int Compare(SemVersion versionA, SemVersion versionB)
+        {
+            if (ReferenceEquals(versionA, null))
+                return ReferenceEquals(versionB, null) ? 0 : -1;
+            return versionA.CompareTo(versionB);
+        }
+
+        /// 
+        /// Make a copy of the current instance with optional altered fields. 
+        /// 
+        /// The major version.
+        /// The minor version.
+        /// The patch version.
+        /// The prerelease text.
+        /// The build text.
+        /// The new version object.
+        public SemVersion Change(int? major = null, int? minor = null, int? patch = null,
+            string prerelease = null, string build = null)
+        {
+            return new SemVersion(
+                major ?? this.Major,
+                minor ?? this.Minor,
+                patch ?? this.Patch,
+                prerelease ?? this.Prerelease,
+                build ?? this.Build);
+        }
+
+        /// 
+        /// Gets the major version.
+        /// 
+        /// 
+        /// The major version.
+        /// 
+        public int Major { get; private set; }
+
+        /// 
+        /// Gets the minor version.
+        /// 
+        /// 
+        /// The minor version.
+        /// 
+        public int Minor { get; private set; }
+
+        /// 
+        /// Gets the patch version.
+        /// 
+        /// 
+        /// The patch version.
+        /// 
+        public int Patch { get; private set; }
+
+        /// 
+        /// Gets the pre-release version.
+        /// 
+        /// 
+        /// The pre-release version.
+        /// 
+        public string Prerelease { get; private set; }
+
+        /// 
+        /// Gets the build version.
+        /// 
+        /// 
+        /// The build version.
+        /// 
+        public string Build { get; private set; }
+
+        /// 
+        /// Returns a  that represents this instance.
+        /// 
+        /// 
+        /// A  that represents this instance.
+        /// 
+        public override string ToString()
+        {
+            var version = "" + Major + "." + Minor + "." + Patch;
+            if (!String.IsNullOrEmpty(Prerelease))
+                version += "-" + Prerelease;
+            if (!String.IsNullOrEmpty(Build))
+                version += "+" + Build;
+            return version;
+        }
+
+        /// 
+        /// Compares the current instance with another object of the same type and returns an integer that indicates 
+        /// whether the current instance precedes, follows, or occurs in the same position in the sort order as the 
+        /// other object.
+        /// 
+        /// An object to compare with this instance.
+        /// 
+        /// A value that indicates the relative order of the objects being compared. 
+        /// The return value has these meanings: Value Meaning Less than zero 
+        ///  This instance precedes  in the sort order. 
+        ///  Zero This instance occurs in the same position in the sort order as . i
+        ///  Greater than zero This instance follows  in the sort order.
+        /// 
+        public int CompareTo(object obj)
+        {
+            return CompareTo((SemVersion)obj);
+        }
+
+        /// 
+        /// Compares the current instance with another object of the same type and returns an integer that indicates 
+        /// whether the current instance precedes, follows, or occurs in the same position in the sort order as the 
+        /// other object.
+        /// 
+        /// An object to compare with this instance.
+        /// 
+        /// A value that indicates the relative order of the objects being compared. 
+        /// The return value has these meanings: Value Meaning Less than zero 
+        ///  This instance precedes  in the sort order. 
+        ///  Zero This instance occurs in the same position in the sort order as . i
+        ///  Greater than zero This instance follows  in the sort order.
+        /// 
+        public int CompareTo(SemVersion other)
+        {
+            if (ReferenceEquals(other, null))
+                return 1;
+
+            var r = this.CompareByPrecedence(other);
+            if (r != 0)
+                return r;
+
+            r = CompareComponent(this.Build, other.Build);
+            return r;
+        }
+
+        /// 
+        /// Compares to semantic versions by precedence. This does the same as a Equals, but ignores the build information.
+        /// 
+        /// The semantic version.
+        /// true if the version precedence matches.
+        public bool PrecedenceMatches(SemVersion other)
+        {
+            return CompareByPrecedence(other) == 0;
+        }
+
+        /// 
+        /// Compares to semantic versions by precedence. This does the same as a Equals, but ignores the build information.
+        /// 
+        /// The semantic version.
+        /// 
+        /// A value that indicates the relative order of the objects being compared. 
+        /// The return value has these meanings: Value Meaning Less than zero 
+        ///  This instance precedes  in the version precedence.
+        ///  Zero This instance has the same precedence as . i
+        ///  Greater than zero This instance has creater precedence as .
+        /// 
+        public int CompareByPrecedence(SemVersion other)
+        {
+            if (ReferenceEquals(other, null))
+                return 1;
+
+            var r = this.Major.CompareTo(other.Major);
+            if (r != 0) return r;
+
+            r = this.Minor.CompareTo(other.Minor);
+            if (r != 0) return r;
+
+            r = this.Patch.CompareTo(other.Patch);
+            if (r != 0) return r;
+
+            r = CompareComponent(this.Prerelease, other.Prerelease, true);
+            return r;
+        }
+
+        static int CompareComponent(string a, string b, bool lower = false)
+        {
+            var aEmpty = String.IsNullOrEmpty(a);
+            var bEmpty = String.IsNullOrEmpty(b);
+            if (aEmpty && bEmpty)
+                return 0;
+
+            if (aEmpty)
+                return lower ? 1 : -1;
+            if (bEmpty)
+                return lower ? -1 : 1;
+
+            var aComps = a.Split('.');
+            var bComps = b.Split('.');
+
+            var minLen = Math.Min(aComps.Length, bComps.Length);
+            for (int i = 0; i < minLen; i++)
+            {
+                var ac = aComps[i];
+                var bc = bComps[i];
+                int anum, bnum;
+                var isanum = Int32.TryParse(ac, out anum);
+                var isbnum = Int32.TryParse(bc, out bnum);
+                int r;
+                if (isanum && isbnum)
+                {
+                    r = anum.CompareTo(bnum);
+                    if (r != 0) return anum.CompareTo(bnum);
+                }
+                else
+                {
+                    if (isanum)
+                        return -1;
+                    if (isbnum)
+                        return 1;
+                    r = String.CompareOrdinal(ac, bc);
+                    if (r != 0)
+                        return r;
+                }
+            }
+
+            return aComps.Length.CompareTo(bComps.Length);
+        }
+
+        /// 
+        /// Determines whether the specified  is equal to this instance.
+        /// 
+        /// The  to compare with this instance.
+        /// 
+        ///   true if the specified  is equal to this instance; otherwise, false.
+        /// 
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(obj, null))
+                return false;
+
+            if (ReferenceEquals(this, obj))
+                return true;
+
+            var other = (SemVersion)obj;
+
+            return this.Major == other.Major &&
+                this.Minor == other.Minor &&
+                this.Patch == other.Patch &&
+                string.Equals(this.Prerelease, other.Prerelease, StringComparison.Ordinal) &&
+                string.Equals(this.Build, other.Build, StringComparison.Ordinal);
+        }
+
+        /// 
+        /// Returns a hash code for this instance.
+        /// 
+        /// 
+        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
+        /// 
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                int result = this.Major.GetHashCode();
+                result = result * 31 + this.Minor.GetHashCode();
+                result = result * 31 + this.Patch.GetHashCode();
+                result = result * 31 + this.Prerelease.GetHashCode();
+                result = result * 31 + this.Build.GetHashCode();
+                return result;
+            }
+        }
+
+#if !NETSTANDARD
+        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
+        public void GetObjectData(SerializationInfo info, StreamingContext context)
+        {
+            if (info == null) throw new ArgumentNullException("info");
+            info.AddValue("SemVersion", ToString());
+        }
+#endif
+
+        /// 
+        /// Implicit conversion from string to SemVersion.
+        /// 
+        /// The semantic version.
+        /// The SemVersion object.
+        public static implicit operator SemVersion(string version)
+        {
+            return SemVersion.Parse(version);
+        }
+
+        /// 
+        /// The override of the equals operator. 
+        /// 
+        /// The left value.
+        /// The right value.
+        /// If left is equal to right true, else false.
+        public static bool operator ==(SemVersion left, SemVersion right)
+        {
+            return SemVersion.Equals(left, right);
+        }
+
+        /// 
+        /// The override of the un-equal operator. 
+        /// 
+        /// The left value.
+        /// The right value.
+        /// If left is not equal to right true, else false.
+        public static bool operator !=(SemVersion left, SemVersion right)
+        {
+            return !SemVersion.Equals(left, right);
+        }
+
+        /// 
+        /// The override of the greater operator. 
+        /// 
+        /// The left value.
+        /// The right value.
+        /// If left is greater than right true, else false.
+        public static bool operator >(SemVersion left, SemVersion right)
+        {
+            return SemVersion.Compare(left, right) > 0;
+        }
+
+        /// 
+        /// The override of the greater than or equal operator. 
+        /// 
+        /// The left value.
+        /// The right value.
+        /// If left is greater than or equal to right true, else false.
+        public static bool operator >=(SemVersion left, SemVersion right)
+        {
+            return left == right || left > right;
+        }
+
+        /// 
+        /// The override of the less operator. 
+        /// 
+        /// The left value.
+        /// The right value.
+        /// If left is less than right true, else false.
+        public static bool operator <(SemVersion left, SemVersion right)
+        {
+            return SemVersion.Compare(left, right) < 0;
+        }
+
+        /// 
+        /// The override of the less than or equal operator. 
+        /// 
+        /// The left value.
+        /// The right value.
+        /// If left is less than or equal to right true, else false.
+        public static bool operator <=(SemVersion left, SemVersion right)
+        {
+            return left == right || left < right;
+        }
+    }
+}
diff --git a/src/Semver/Semver.xproj b/src/Semver/Semver.xproj
new file mode 100644
index 0000000..ccdb9b3
--- /dev/null
+++ b/src/Semver/Semver.xproj
@@ -0,0 +1,19 @@
+
+
+  
+    14.0
+    $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+  
+  
+  
+    da3e84c8-a960-420c-a85a-718005aacc36
+    Semver
+    .\obj
+    .\bin\
+  
+
+  
+    2.0
+  
+  
+
\ No newline at end of file
diff --git a/src/Semver/project.json b/src/Semver/project.json
new file mode 100644
index 0000000..931da6c
--- /dev/null
+++ b/src/Semver/project.json
@@ -0,0 +1,53 @@
+{
+    "version": "99.99.99-dev",
+    "title": "Semantic versioning",
+    "description": "A semver implementation in .Net based on the v2.0.0 of the spec found at http://semver.org/.",
+    "authors": [ "Max Hauser" ],
+    "copyright": "Copyright (c) 2013",
+    "packOptions": {
+        "tags": [ "semver", "semantic", "version" ],
+        "owners": [ "Max Hauser" ],
+        "projectUrl": "https://github.com/maxhauser/semver",
+        "releaseNotes": "https://github.com/maxhauser/semver/releases",
+        "licenseUrl": "http://max.mit-license.org/",
+        "repository": {
+            "type": "git",
+            "url": "https://github.com/maxhauser/semver"
+        }
+    },
+    "buildOptions": {
+        "debugType": "portable",
+        "nowarn": [
+            "CS1591"
+        ],
+        "optimize": true,
+        "warningsAsErrors": true,
+        "xmlDoc": true
+    },
+    "frameworks": {
+        "netstandard1.1": {
+            "buildOptions": {
+                "define": [ "NETSTANDARD", "NETSTANDARD1_1" ]
+            },
+            "dependencies": {
+                "System.Runtime": "4.1.0",
+                "System.Runtime.Extensions": "4.1.0",
+                "System.Runtime.InteropServices": "4.1.0",
+                "System.Text.RegularExpressions": "4.1.0"
+            }
+        },
+        "net452": {
+            "buildOptions": {
+                "define": [ "NET45" ]
+            },
+            "frameworkAssemblies": {
+                "System.Runtime": {
+                    "type": "build"
+                },
+                "System.Threading.Tasks": {
+                    "type": "build"
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Semver.Test/Properties/AssemblyInfo.cs b/test/Semver.Test/Properties/AssemblyInfo.cs
similarity index 100%
rename from Semver.Test/Properties/AssemblyInfo.cs
rename to test/Semver.Test/Properties/AssemblyInfo.cs
diff --git a/Semver.Test/SemVersionTest.cs b/test/Semver.Test/SemVersionTest.cs
similarity index 54%
rename from Semver.Test/SemVersionTest.cs
rename to test/Semver.Test/SemVersionTest.cs
index 153528f..d3c6e6c 100644
--- a/Semver.Test/SemVersionTest.cs
+++ b/test/Semver.Test/SemVersionTest.cs
@@ -1,796 +1,777 @@
-using System;
-using System.IO;
-using System.Runtime.Serialization;
-using System.Runtime.Serialization.Formatters.Binary;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace Semver.Test
-{
-    [TestClass]
-    public class SemverTests
-    {
-        [TestMethod]
-        public void CompareTestWithStrings1()
-        {
-            Assert.IsTrue(SemVersion.Equals("1.0.0", "1"));
-        }
-
-        [TestMethod]
-        public void CompareTestWithStrings2()
-        {
-            var v = new SemVersion(1, 0, 0);
-            Assert.IsTrue(v < "1.1");
-        }
-
-        [TestMethod]
-        public void CompareTestWithStrings3()
-        {
-            var v = new SemVersion(1, 2);
-            Assert.IsTrue(v > "1.0.0");
-        }
-
-        [TestMethod]
-        public void CreateVersionTest()
-        {
-            var v = new SemVersion(1, 2, 3, "a", "b");
-
-            Assert.AreEqual(1, v.Major);
-            Assert.AreEqual(2, v.Minor);
-            Assert.AreEqual(3, v.Patch);
-            Assert.AreEqual("a", v.Prerelease);
-            Assert.AreEqual("b", v.Build);
-        }
-
-        [TestMethod]
-        public void CreateVersionTestWithNulls()
-        {
-            var v = new SemVersion(1, 2, 3, null, null);
-
-            Assert.AreEqual(1, v.Major);
-            Assert.AreEqual(2, v.Minor);
-            Assert.AreEqual(3, v.Patch);
-            Assert.AreEqual("", v.Prerelease);
-            Assert.AreEqual("", v.Build);
-        }
-
-        [TestMethod]
-        public void CreateVersionTestWithSystemVersion1()
-        {
-            var nonSemanticVersion = new Version();
-            var v = new SemVersion(nonSemanticVersion);
-
-            Assert.AreEqual(0, v.Major);
-            Assert.AreEqual(0, v.Minor);
-            Assert.AreEqual(0, v.Patch);
-            Assert.AreEqual("", v.Build);
-            Assert.AreEqual("", v.Prerelease);
-        }
-
-        [TestMethod]
-        public void CreateVersionTestWithSystemVersion2()
-        {
-            var v = new SemVersion(null);
-
-            Assert.AreEqual(0, v.Major);
-            Assert.AreEqual(0, v.Minor);
-            Assert.AreEqual(0, v.Patch);
-            Assert.AreEqual("", v.Build);
-            Assert.AreEqual("", v.Prerelease);
-        }
-
-        [TestMethod]
-        public void CreateVersionTestWithSystemVersion3()
-        {
-            var nonSemanticVersion = new Version(1, 2, 0, 3);
-            var v = new SemVersion(nonSemanticVersion);
-
-            Assert.AreEqual(1, v.Major);
-            Assert.AreEqual(2, v.Minor);
-            Assert.AreEqual(3, v.Patch);
-            Assert.AreEqual("", v.Build);
-            Assert.AreEqual("", v.Prerelease);
-        }
-
-        [TestMethod]
-        public void CreateVersionTestWithSystemVersion4()
-        {
-            var nonSemanticVersion = new Version(1, 2, 4, 3);
-            var v = new SemVersion(nonSemanticVersion);
-
-            Assert.AreEqual(1, v.Major);
-            Assert.AreEqual(2, v.Minor);
-            Assert.AreEqual(3, v.Patch);
-            Assert.AreEqual("4", v.Build);
-            Assert.AreEqual("", v.Prerelease);
-        }
-
-        [TestMethod]
-        public void ParseTest1()
-        {
-            var version = SemVersion.Parse("1.2.45-alpha+nightly.23");
-
-            Assert.AreEqual(1, version.Major);
-            Assert.AreEqual(2, version.Minor);
-            Assert.AreEqual(45, version.Patch);
-            Assert.AreEqual("alpha", version.Prerelease);
-            Assert.AreEqual("nightly.23", version.Build);
-        }
-
-        [TestMethod]
-        public void ParseTest2()
-        {
-            var version = SemVersion.Parse("1");
-
-            Assert.AreEqual(1, version.Major);
-            Assert.AreEqual(0, version.Minor);
-            Assert.AreEqual(0, version.Patch);
-            Assert.AreEqual("", version.Prerelease);
-            Assert.AreEqual("", version.Build);
-        }
-
-        [TestMethod]
-        public void ParseTest3()
-        {
-            var version = SemVersion.Parse("1.2.45-alpha-beta+nightly.23.43-bla");
-
-            Assert.AreEqual(1, version.Major);
-            Assert.AreEqual(2, version.Minor);
-            Assert.AreEqual(45, version.Patch);
-            Assert.AreEqual("alpha-beta", version.Prerelease);
-            Assert.AreEqual("nightly.23.43-bla", version.Build);
-        }
-
-        [TestMethod]
-        public void ParseTest4()
-        {
-            var version = SemVersion.Parse("2.0.0+nightly.23.43-bla");
-
-            Assert.AreEqual(2, version.Major);
-            Assert.AreEqual(0, version.Minor);
-            Assert.AreEqual(0, version.Patch);
-            Assert.AreEqual("", version.Prerelease);
-            Assert.AreEqual("nightly.23.43-bla", version.Build);
-        }
-
-        [TestMethod]
-        public void ParseTest5()
-        {
-            var version = SemVersion.Parse("2.0+nightly.23.43-bla");
-
-            Assert.AreEqual(2, version.Major);
-            Assert.AreEqual(0, version.Minor);
-            Assert.AreEqual(0, version.Patch);
-            Assert.AreEqual("", version.Prerelease);
-            Assert.AreEqual("nightly.23.43-bla", version.Build);
-        }
-
-        [TestMethod]
-        public void ParseTest6()
-        {
-            var version = SemVersion.Parse("2.1-alpha");
-
-            Assert.AreEqual(2, version.Major);
-            Assert.AreEqual(1, version.Minor);
-            Assert.AreEqual(0, version.Patch);
-            Assert.AreEqual("alpha", version.Prerelease);
-            Assert.AreEqual("", version.Build);
-        }
-
-        [TestMethod]
-        [ExpectedException(typeof(ArgumentException))]
-        public void ParseTest7()
-        {
-            var version = SemVersion.Parse("ui-2.1-alpha");
-        }
-
-        [TestMethod]
-        public void ParseTestStrict1()
-        {
-            var version = SemVersion.Parse("1.3.4", true);
-
-            Assert.AreEqual(1, version.Major);
-            Assert.AreEqual(3, version.Minor);
-            Assert.AreEqual(4, version.Patch);
-            Assert.AreEqual("", version.Prerelease);
-            Assert.AreEqual("", version.Build);
-        }
-
-        [TestMethod]
-        [ExpectedException(typeof(InvalidOperationException))]
-        public void ParseTestStrict2()
-        {
-            var version = SemVersion.Parse("1", true);
-        }
-
-        [TestMethod]
-        [ExpectedException(typeof(InvalidOperationException))]
-        public void ParseTestStrict3()
-        {
-            var version = SemVersion.Parse("1.3", true);
-        }
-
-        [TestMethod]
-        [ExpectedException(typeof(InvalidOperationException))]
-        public void ParseTestStrict4()
-        {
-            var version = SemVersion.Parse("1.3-alpha", true);
-        }
-
-        [TestMethod]
-        public void TryParseTest1()
-        {
-            SemVersion v;
-            Assert.IsTrue(SemVersion.TryParse("1.2.45-alpha-beta+nightly.23.43-bla", out v));
-        }
-
-        [TestMethod]
-        public void TryParseTest2()
-        {
-            SemVersion v;
-            Assert.IsFalse(SemVersion.TryParse("ui-2.1-alpha", out v));
-        }
-
-        [TestMethod]
-        public void TryParseTest3()
-        {
-            SemVersion v;
-            Assert.IsFalse(SemVersion.TryParse("", out v));
-        }
-
-        [TestMethod]
-        public void TryParseTest4()
-        {
-            SemVersion v;
-            Assert.IsFalse(SemVersion.TryParse(null, out v));
-        }
-
-        [TestMethod]
-        public void TryParseTest5()
-        {
-            SemVersion v;
-            Assert.IsTrue(SemVersion.TryParse("1.2", out v, false));
-        }
-
-        [TestMethod]
-        public void TryParseTest6()
-        {
-            SemVersion v;
-            Assert.IsFalse(SemVersion.TryParse("1.2", out v, true));
-        }
-
-        [TestMethod]
-        public void ToStringTest()
-        {
-            var version = new SemVersion(1, 2, 0, "beta", "dev-mha.120");
-
-            Assert.AreEqual("1.2.0-beta+dev-mha.120", version.ToString());
-        }
-
-        [TestMethod]
-        public void EqualTest1()
-        {
-            var v1 = new SemVersion(1, 2, build: "nightly");
-            var v2 = new SemVersion(1, 2, build: "nightly");
-
-            var r = v1.Equals(v2);
-            Assert.IsTrue(r);
-        }
-
-        [TestMethod]
-        public void EqualTest2()
-        {
-            var v1 = new SemVersion(1, 2, prerelease: "alpha", build: "dev");
-            var v2 = new SemVersion(1, 2, prerelease: "alpha", build: "dev");
-
-            var r = v1.Equals(v2);
-            Assert.IsTrue(r);
-        }
-
-        [TestMethod]
-        public void EqualTest3()
-        {
-            var v1 = SemVersion.Parse("1.2-nightly+dev");
-            var v2 = SemVersion.Parse("1.2.0-nightly");
-
-            var r = v1.Equals(v2);
-            Assert.IsFalse(r);
-        }
-
-        [TestMethod]
-        public void EqualTest4()
-        {
-            var v1 = SemVersion.Parse("1.2-nightly");
-            var v2 = SemVersion.Parse("1.2.0-nightly2");
-
-            var r = v1.Equals(v2);
-            Assert.IsFalse(r);
-        }
-
-        [TestMethod]
-        public void EqualTest5()
-        {
-            var v1 = SemVersion.Parse("1.2.1");
-            var v2 = SemVersion.Parse("1.2.0");
-
-            var r = v1.Equals(v2);
-            Assert.IsFalse(r);
-        }
-
-        [TestMethod]
-        public void EqualTest6()
-        {
-            var v1 = SemVersion.Parse("1.4.0");
-            var v2 = SemVersion.Parse("1.2.0");
-
-            var r = v1.Equals(v2);
-            Assert.IsFalse(r);
-        }
-
-        [TestMethod]
-        public void EqualByReferenceTest()
-        {
-            var v1 = SemVersion.Parse("1.2-nightly");
-
-            var r = v1.Equals(v1);
-            Assert.IsTrue(r);
-        }
-
-        [TestMethod]
-        public void CompareTest1()
-        {
-            var v1 = SemVersion.Parse("1.0.0");
-            var v2 = SemVersion.Parse("2.0.0");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(-1, r);
-        }
-
-        [TestMethod]
-        public void CompareTest2()
-        {
-            var v1 = SemVersion.Parse("1.0.0-beta+dev.123");
-            var v2 = SemVersion.Parse("1-beta+dev.123");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(0, r);
-        }
-
-        [TestMethod]
-        public void CompareTest3()
-        {
-            var v1 = SemVersion.Parse("1.0.0-alpha+dev.123");
-            var v2 = SemVersion.Parse("1-beta+dev.123");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(-1, r);
-        }
-
-        [TestMethod]
-        public void CompareTest4()
-        {
-            var v1 = SemVersion.Parse("1.0.0-alpha");
-            var v2 = SemVersion.Parse("1.0.0");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(-1, r);
-        }
-
-        [TestMethod]
-        public void CompareTest5()
-        {
-            var v1 = SemVersion.Parse("1.0.0");
-            var v2 = SemVersion.Parse("1.0.0-alpha");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(1, r);
-        }
-
-        [TestMethod]
-        public void CompareTest6()
-        {
-            var v1 = SemVersion.Parse("1.0.0");
-            var v2 = SemVersion.Parse("1.0.1-alpha");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(-1, r);
-        }
-
-        [TestMethod]
-        public void CompareTest7()
-        {
-            var v1 = SemVersion.Parse("0.0.1");
-            var v2 = SemVersion.Parse("0.0.1+build.12");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(-1, r);
-        }
-
-        [TestMethod]
-        public void CompareTest8()
-        {
-            var v1 = SemVersion.Parse("0.0.1+build.13");
-            var v2 = SemVersion.Parse("0.0.1+build.12.2");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(1, r);
-        }
-
-        [TestMethod]
-        public void CompareTest9()
-        {
-            var v1 = SemVersion.Parse("0.0.1-13");
-            var v2 = SemVersion.Parse("0.0.1-b");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(-1, r);
-        }
-
-        [TestMethod]
-        public void CompareTest10()
-        {
-            var v1 = SemVersion.Parse("0.0.1+uiui");
-            var v2 = SemVersion.Parse("0.0.1+12");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(1, r);
-        }
-
-        [TestMethod]
-        public void CompareTest11()
-        {
-            var v1 = SemVersion.Parse("0.0.1+bu");
-            var v2 = SemVersion.Parse("0.0.1");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(1, r);
-        }
-
-        [TestMethod]
-        public void CompareTest12()
-        {
-            var v1 = SemVersion.Parse("0.1.1+bu");
-            var v2 = SemVersion.Parse("0.2.1");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(-1, r);
-        }
-
-        [TestMethod]
-        public void CompareTest13()
-        {
-            var v1 = SemVersion.Parse("0.1.1-gamma.12.87");
-            var v2 = SemVersion.Parse("0.1.1-gamma.12.88");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(-1, r);
-        }
-
-        [TestMethod]
-        public void CompareTest14()
-        {
-            var v1 = SemVersion.Parse("0.1.1-gamma.12.87");
-            var v2 = SemVersion.Parse("0.1.1-gamma.12.87.1");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(-1, r);
-        }
-
-        [TestMethod]
-        public void CompareTest15()
-        {
-            var v1 = SemVersion.Parse("0.1.1-gamma.12.87.99");
-            var v2 = SemVersion.Parse("0.1.1-gamma.12.87.X");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(-1, r);
-        }
-
-        [TestMethod]
-        public void CompareTest16()
-        {
-            var v1 = SemVersion.Parse("0.1.1-gamma.12.87");
-            var v2 = SemVersion.Parse("0.1.1-gamma.12.87.X");
-
-            var r = v1.CompareTo(v2);
-            Assert.AreEqual(-1, r);
-        }
-
-        [TestMethod]
-        public void CompareNullTest()
-        {
-            var v1 = SemVersion.Parse("0.0.1+bu");
-            var r = v1.CompareTo(null);
-            Assert.AreEqual(1, r);
-        }
-
-        [TestMethod]
-        public void TestHashCode()
-        {
-            var v1 = SemVersion.Parse("1.0.0-1+b");
-            var v2 = SemVersion.Parse("1.0.0-1+c");
-
-            var h1 = v1.GetHashCode();
-            var h2 = v2.GetHashCode();
-
-            Assert.AreNotEqual(h1, h2);
-        }
-
-        [TestMethod]
-        public void TestStringConversion()
-        {
-            SemVersion v = "1.0.0";
-            Assert.AreEqual(1, v.Major);
-        }
-
-        [TestMethod]
-        public void TestUntypedCompareTo()
-        {
-            var v1 = new SemVersion(1);
-            var c = v1.CompareTo((object)v1);
-
-            Assert.AreEqual(0, c);
-        }
-
-        [TestMethod]
-        public void StaticEqualsTest1()
-        {
-            var v1 = new SemVersion(1, 2, 3);
-            var v2 = new SemVersion(1, 2, 3);
-
-            var r = SemVersion.Equals(v1, v2);
-            Assert.IsTrue(r);
-        }
-
-        [TestMethod]
-        public void StaticEqualsTest2()
-        {
-            var r = SemVersion.Equals(null, null);
-            Assert.IsTrue(r);
-        }
-
-        [TestMethod]
-        public void StaticEqualsTest3()
-        {
-            var v1 = new SemVersion(1);
-
-            var r = SemVersion.Equals(v1, null);
-            Assert.IsFalse(r);
-        }
-
-        [TestMethod]
-        public void StaticCompareTest1()
-        {
-            var v1 = new SemVersion(1);
-            var v2 = new SemVersion(2);
-
-            var r = SemVersion.Compare(v1, v2);
-            Assert.AreEqual(-1, r);
-        }
-
-        [TestMethod]
-        public void StaticCompareTest2()
-        {
-            var v1 = new SemVersion(1);
-
-            var r = SemVersion.Compare(v1, null);
-            Assert.AreEqual(1, r);
-        }
-
-        [TestMethod]
-        public void StaticCompareTest3()
-        {
-            var v1 = new SemVersion(1);
-
-            var r = SemVersion.Compare(null, v1);
-            Assert.AreEqual(-1, r);
-        }
-
-        [TestMethod]
-        public void StaticCompareTest4()
-        {
-            var r = SemVersion.Compare(null, null);
-            Assert.AreEqual(0, r);
-        }
-
-        [TestMethod]
-        public void EqualsOperatorTest()
-        {
-            var v1 = new SemVersion(1);
-            var v2 = new SemVersion(1);
-
-            var r = v1 == v2;
-            Assert.IsTrue(r);
-        }
-
-        [TestMethod]
-        public void UnequalOperatorTest()
-        {
-            var v1 = new SemVersion(1);
-            var v2 = new SemVersion(2);
-
-            var r = v1 != v2;
-            Assert.IsTrue(r);
-        }
-
-        [TestMethod]
-        public void GreaterOperatorTest()
-        {
-            var v1 = new SemVersion(1);
-            var v2 = new SemVersion(2);
-
-            var r = v2 > v1;
-            Assert.IsTrue(r);
-        }
-
-        [TestMethod]
-        public void GreaterOperatorTest2()
-        {
-            var v1 = new SemVersion( 1, 0, 0, "alpha" );
-            var v2 = new SemVersion( 1, 0, 0, "rc" );
-
-            var r = v2 > v1;
-            Assert.IsTrue( r );
-        }
-
-        [TestMethod]
-        public void GreaterOperatorTest3()
-        {
-            var v1 = new SemVersion( 1, 0, 0, "-ci.1" );
-            var v2 = new SemVersion( 1, 0, 0, "alpha" );
-
-            var r = v2 > v1;
-            Assert.IsTrue( r );
-        }
-
-        [TestMethod]
-        public void GreaterOrEqualOperatorTest1()
-        {
-            var v1 = new SemVersion(1);
-            var v2 = new SemVersion(1);
-
-            var r = v1 >= v2;
-            Assert.IsTrue(r);
-        }
-
-        [TestMethod]
-        public void GreaterOrEqualOperatorTest2()
-        {
-            var v1 = new SemVersion(2);
-            var v2 = new SemVersion(1);
-
-            var r = v1 >= v2;
-            Assert.IsTrue(r);
-        }
-
-        [TestMethod]
-        public void LessOperatorTest()
-        {
-            var v1 = new SemVersion(1);
-            var v2 = new SemVersion(2);
-
-            var r = v1 < v2;
-            Assert.IsTrue(r);
-        }
-
-        [TestMethod]
-        public void LessOperatorTest2()
-        {
-            var v1 = new SemVersion( 1, 0, 0, "alpha" );
-            var v2 = new SemVersion( 1, 0, 0, "rc" );
-
-            var r = v1 < v2;
-            Assert.IsTrue( r );
-        }
-
-        [TestMethod]
-        public void LessOperatorTest3()
-        {
-            var v1 = new SemVersion( 1, 0, 0, "-ci.1" );
-            var v2 = new SemVersion( 1, 0, 0, "alpha" );
-
-            var r = v1 < v2;
-            Assert.IsTrue( r );
-        }
-
-        [TestMethod]
-        public void LessOrEqualOperatorTest1()
-        {
-            var v1 = new SemVersion(1);
-            var v2 = new SemVersion(1);
-
-            var r = v1 <= v2;
-            Assert.IsTrue(r);
-        }
-
-        [TestMethod]
-        public void LessOrEqualOperatorTest2()
-        {
-            var v1 = new SemVersion(1);
-            var v2 = new SemVersion(2);
-
-            var r = v1 <= v2;
-            Assert.IsTrue(r);
-        }
-
-        [TestMethod]
-        public void TestChangeMajor()
-        {
-            var v1 = new SemVersion(1, 2, 3, "alpha", "dev");
-            var v2 = v1.Change(major: 5);
-
-            Assert.AreEqual(5, v2.Major);
-            Assert.AreEqual(2, v2.Minor);
-            Assert.AreEqual(3, v2.Patch);
-            Assert.AreEqual("alpha", v2.Prerelease);
-            Assert.AreEqual("dev", v2.Build);
-        }
-
-        [TestMethod]
-        public void TestChangeMinor()
-        {
-            var v1 = new SemVersion(1, 2, 3, "alpha", "dev");
-            var v2 = v1.Change(minor: 5);
-
-            Assert.AreEqual(1, v2.Major);
-            Assert.AreEqual(5, v2.Minor);
-            Assert.AreEqual(3, v2.Patch);
-            Assert.AreEqual("alpha", v2.Prerelease);
-            Assert.AreEqual("dev", v2.Build);
-        }
-
-        [TestMethod]
-        public void TestChangePatch()
-        {
-            var v1 = new SemVersion(1, 2, 3, "alpha", "dev");
-            var v2 = v1.Change(patch: 5);
-
-            Assert.AreEqual(1, v2.Major);
-            Assert.AreEqual(2, v2.Minor);
-            Assert.AreEqual(5, v2.Patch);
-            Assert.AreEqual("alpha", v2.Prerelease);
-            Assert.AreEqual("dev", v2.Build);
-        }
-
-        [TestMethod]
-        public void TestChangePrerelease()
-        {
-            var v1 = new SemVersion(1, 2, 3, "alpha", "dev");
-            var v2 = v1.Change(prerelease: "beta");
-
-            Assert.AreEqual(1, v2.Major);
-            Assert.AreEqual(2, v2.Minor);
-            Assert.AreEqual(3, v2.Patch);
-            Assert.AreEqual("beta", v2.Prerelease);
-            Assert.AreEqual("dev", v2.Build);
-        }
-
-        [TestMethod]
-        public void TestChangeBuild()
-        {
-            var v1 = new SemVersion(1, 2, 3, "alpha", "dev");
-            var v2 = v1.Change(build: "rel");
-
-            Assert.AreEqual(1, v2.Major);
-            Assert.AreEqual(2, v2.Minor);
-            Assert.AreEqual(3, v2.Patch);
-            Assert.AreEqual("alpha", v2.Prerelease);
-            Assert.AreEqual("rel", v2.Build);
-        }
-
-        [TestMethod]
-        public void TestSerialization()
-        {
-            var semVer = new SemVersion(1, 2, 3, "alpha", "dev");
-            SemVersion semVerSerializedDeserialized;
-            using (var ms = new MemoryStream())
-            {
-                var bf = new BinaryFormatter();
-                bf.Serialize(ms, semVer);
-                ms.Position = 0;
-                semVerSerializedDeserialized = (SemVersion) bf.Deserialize(ms);
-            }
-            Assert.AreEqual(semVer, semVerSerializedDeserialized);
-        }
-
-    }
-}
+using System;
+using System.IO;
+#if !NETSTANDARD
+using System.Runtime.Serialization.Formatters.Binary;
+#endif
+using Xunit;
+
+namespace Semver.Test
+{
+    public class SemverTests
+    {
+        [Fact]
+        public void CompareTestWithStrings1()
+        {
+            Assert.True(SemVersion.Equals("1.0.0", "1"));
+        }
+
+        [Fact]
+        public void CompareTestWithStrings2()
+        {
+            var v = new SemVersion(1, 0, 0);
+            Assert.True(v < "1.1");
+        }
+
+        [Fact]
+        public void CompareTestWithStrings3()
+        {
+            var v = new SemVersion(1, 2);
+            Assert.True(v > "1.0.0");
+        }
+
+        [Fact]
+        public void CreateVersionTest()
+        {
+            var v = new SemVersion(1, 2, 3, "a", "b");
+
+            Assert.Equal(1, v.Major);
+            Assert.Equal(2, v.Minor);
+            Assert.Equal(3, v.Patch);
+            Assert.Equal("a", v.Prerelease);
+            Assert.Equal("b", v.Build);
+        }
+
+        [Fact]
+        public void CreateVersionTestWithNulls()
+        {
+            var v = new SemVersion(1, 2, 3, null, null);
+
+            Assert.Equal(1, v.Major);
+            Assert.Equal(2, v.Minor);
+            Assert.Equal(3, v.Patch);
+            Assert.Equal("", v.Prerelease);
+            Assert.Equal("", v.Build);
+        }
+
+        [Fact]
+        public void CreateVersionTestWithSystemVersion1()
+        {
+            var nonSemanticVersion = new Version(0, 0);
+            var v = new SemVersion(nonSemanticVersion);
+
+            Assert.Equal(0, v.Major);
+            Assert.Equal(0, v.Minor);
+            Assert.Equal(0, v.Patch);
+            Assert.Equal("", v.Build);
+            Assert.Equal("", v.Prerelease);
+        }
+
+        [Fact]
+        public void CreateVersionTestWithSystemVersion2()
+        {
+            Assert.Throws(typeof(ArgumentNullException), () =>
+            {
+                var v = new SemVersion(null);
+            });
+        }
+
+        [Fact]
+        public void CreateVersionTestWithSystemVersion3()
+        {
+            var nonSemanticVersion = new Version(1, 2, 0, 3);
+            var v = new SemVersion(nonSemanticVersion);
+
+            Assert.Equal(1, v.Major);
+            Assert.Equal(2, v.Minor);
+            Assert.Equal(3, v.Patch);
+            Assert.Equal("", v.Build);
+            Assert.Equal("", v.Prerelease);
+        }
+
+        [Fact]
+        public void CreateVersionTestWithSystemVersion4()
+        {
+            var nonSemanticVersion = new Version(1, 2, 4, 3);
+            var v = new SemVersion(nonSemanticVersion);
+
+            Assert.Equal(1, v.Major);
+            Assert.Equal(2, v.Minor);
+            Assert.Equal(3, v.Patch);
+            Assert.Equal("4", v.Build);
+            Assert.Equal("", v.Prerelease);
+        }
+
+        [Fact]
+        public void ParseTest1()
+        {
+            var version = SemVersion.Parse("1.2.45-alpha+nightly.23");
+
+            Assert.Equal(1, version.Major);
+            Assert.Equal(2, version.Minor);
+            Assert.Equal(45, version.Patch);
+            Assert.Equal("alpha", version.Prerelease);
+            Assert.Equal("nightly.23", version.Build);
+        }
+
+        [Fact]
+        public void ParseTest2()
+        {
+            var version = SemVersion.Parse("1");
+
+            Assert.Equal(1, version.Major);
+            Assert.Equal(0, version.Minor);
+            Assert.Equal(0, version.Patch);
+            Assert.Equal("", version.Prerelease);
+            Assert.Equal("", version.Build);
+        }
+
+        [Fact]
+        public void ParseTest3()
+        {
+            var version = SemVersion.Parse("1.2.45-alpha-beta+nightly.23.43-bla");
+
+            Assert.Equal(1, version.Major);
+            Assert.Equal(2, version.Minor);
+            Assert.Equal(45, version.Patch);
+            Assert.Equal("alpha-beta", version.Prerelease);
+            Assert.Equal("nightly.23.43-bla", version.Build);
+        }
+
+        [Fact]
+        public void ParseTest4()
+        {
+            var version = SemVersion.Parse("2.0.0+nightly.23.43-bla");
+
+            Assert.Equal(2, version.Major);
+            Assert.Equal(0, version.Minor);
+            Assert.Equal(0, version.Patch);
+            Assert.Equal("", version.Prerelease);
+            Assert.Equal("nightly.23.43-bla", version.Build);
+        }
+
+        [Fact]
+        public void ParseTest5()
+        {
+            var version = SemVersion.Parse("2.0+nightly.23.43-bla");
+
+            Assert.Equal(2, version.Major);
+            Assert.Equal(0, version.Minor);
+            Assert.Equal(0, version.Patch);
+            Assert.Equal("", version.Prerelease);
+            Assert.Equal("nightly.23.43-bla", version.Build);
+        }
+
+        [Fact]
+        public void ParseTest6()
+        {
+            var version = SemVersion.Parse("2.1-alpha");
+
+            Assert.Equal(2, version.Major);
+            Assert.Equal(1, version.Minor);
+            Assert.Equal(0, version.Patch);
+            Assert.Equal("alpha", version.Prerelease);
+            Assert.Equal("", version.Build);
+        }
+
+        [Fact]
+        public void ParseTest7()
+        {
+            Assert.Throws(() => SemVersion.Parse("ui-2.1-alpha"));
+        }
+
+        [Fact]
+        public void ParseTestStrict1()
+        {
+            var version = SemVersion.Parse("1.3.4", true);
+
+            Assert.Equal(1, version.Major);
+            Assert.Equal(3, version.Minor);
+            Assert.Equal(4, version.Patch);
+            Assert.Equal("", version.Prerelease);
+            Assert.Equal("", version.Build);
+        }
+
+        [Fact]
+        public void ParseTestStrict2()
+        {
+            Assert.Throws(() => SemVersion.Parse("1", true));
+        }
+
+        [Fact]
+        public void ParseTestStrict3()
+        {
+            Assert.Throws(() => SemVersion.Parse("1.3", true));
+        }
+
+        [Fact]
+        public void ParseTestStrict4()
+        {
+            Assert.Throws(() => SemVersion.Parse("1.3-alpha", true));
+        }
+
+        [Fact]
+        public void TryParseTest1()
+        {
+            SemVersion v;
+            Assert.True(SemVersion.TryParse("1.2.45-alpha-beta+nightly.23.43-bla", out v));
+        }
+
+        [Fact]
+        public void TryParseTest2()
+        {
+            SemVersion v;
+            Assert.False(SemVersion.TryParse("ui-2.1-alpha", out v));
+        }
+
+        [Fact]
+        public void TryParseTest3()
+        {
+            SemVersion v;
+            Assert.False(SemVersion.TryParse("", out v));
+        }
+
+        [Fact]
+        public void TryParseTest4()
+        {
+            SemVersion v;
+            Assert.False(SemVersion.TryParse(null, out v));
+        }
+
+        [Fact]
+        public void TryParseTest5()
+        {
+            SemVersion v;
+            Assert.True(SemVersion.TryParse("1.2", out v, false));
+        }
+
+        [Fact]
+        public void TryParseTest6()
+        {
+            SemVersion v;
+            Assert.False(SemVersion.TryParse("1.2", out v, true));
+        }
+
+        [Fact]
+        public void ToStringTest()
+        {
+            var version = new SemVersion(1, 2, 0, "beta", "dev-mha.120");
+
+            Assert.Equal("1.2.0-beta+dev-mha.120", version.ToString());
+        }
+
+        [Fact]
+        public void EqualTest1()
+        {
+            var v1 = new SemVersion(1, 2, build: "nightly");
+            var v2 = new SemVersion(1, 2, build: "nightly");
+
+            var r = v1.Equals(v2);
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void EqualTest2()
+        {
+            var v1 = new SemVersion(1, 2, prerelease: "alpha", build: "dev");
+            var v2 = new SemVersion(1, 2, prerelease: "alpha", build: "dev");
+
+            var r = v1.Equals(v2);
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void EqualTest3()
+        {
+            var v1 = SemVersion.Parse("1.2-nightly+dev");
+            var v2 = SemVersion.Parse("1.2.0-nightly");
+
+            var r = v1.Equals(v2);
+            Assert.False(r);
+        }
+
+        [Fact]
+        public void EqualTest4()
+        {
+            var v1 = SemVersion.Parse("1.2-nightly");
+            var v2 = SemVersion.Parse("1.2.0-nightly2");
+
+            var r = v1.Equals(v2);
+            Assert.False(r);
+        }
+
+        [Fact]
+        public void EqualTest5()
+        {
+            var v1 = SemVersion.Parse("1.2.1");
+            var v2 = SemVersion.Parse("1.2.0");
+
+            var r = v1.Equals(v2);
+            Assert.False(r);
+        }
+
+        [Fact]
+        public void EqualTest6()
+        {
+            var v1 = SemVersion.Parse("1.4.0");
+            var v2 = SemVersion.Parse("1.2.0");
+
+            var r = v1.Equals(v2);
+            Assert.False(r);
+        }
+
+        [Fact]
+        public void EqualByReferenceTest()
+        {
+            var v1 = SemVersion.Parse("1.2-nightly");
+
+            var r = v1.Equals(v1);
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void CompareTest1()
+        {
+            var v1 = SemVersion.Parse("1.0.0");
+            var v2 = SemVersion.Parse("2.0.0");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(-1, r);
+        }
+
+        [Fact]
+        public void CompareTest2()
+        {
+            var v1 = SemVersion.Parse("1.0.0-beta+dev.123");
+            var v2 = SemVersion.Parse("1-beta+dev.123");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(0, r);
+        }
+
+        [Fact]
+        public void CompareTest3()
+        {
+            var v1 = SemVersion.Parse("1.0.0-alpha+dev.123");
+            var v2 = SemVersion.Parse("1-beta+dev.123");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(-1, r);
+        }
+
+        [Fact]
+        public void CompareTest4()
+        {
+            var v1 = SemVersion.Parse("1.0.0-alpha");
+            var v2 = SemVersion.Parse("1.0.0");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(-1, r);
+        }
+
+        [Fact]
+        public void CompareTest5()
+        {
+            var v1 = SemVersion.Parse("1.0.0");
+            var v2 = SemVersion.Parse("1.0.0-alpha");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(1, r);
+        }
+
+        [Fact]
+        public void CompareTest6()
+        {
+            var v1 = SemVersion.Parse("1.0.0");
+            var v2 = SemVersion.Parse("1.0.1-alpha");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(-1, r);
+        }
+
+        [Fact]
+        public void CompareTest7()
+        {
+            var v1 = SemVersion.Parse("0.0.1");
+            var v2 = SemVersion.Parse("0.0.1+build.12");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(-1, r);
+        }
+
+        [Fact]
+        public void CompareTest8()
+        {
+            var v1 = SemVersion.Parse("0.0.1+build.13");
+            var v2 = SemVersion.Parse("0.0.1+build.12.2");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(1, r);
+        }
+
+        [Fact]
+        public void CompareTest9()
+        {
+            var v1 = SemVersion.Parse("0.0.1-13");
+            var v2 = SemVersion.Parse("0.0.1-b");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(-1, r);
+        }
+
+        [Fact]
+        public void CompareTest10()
+        {
+            var v1 = SemVersion.Parse("0.0.1+uiui");
+            var v2 = SemVersion.Parse("0.0.1+12");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(1, r);
+        }
+
+        [Fact]
+        public void CompareTest11()
+        {
+            var v1 = SemVersion.Parse("0.0.1+bu");
+            var v2 = SemVersion.Parse("0.0.1");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(1, r);
+        }
+
+        [Fact]
+        public void CompareTest12()
+        {
+            var v1 = SemVersion.Parse("0.1.1+bu");
+            var v2 = SemVersion.Parse("0.2.1");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(-1, r);
+        }
+
+        [Fact]
+        public void CompareTest13()
+        {
+            var v1 = SemVersion.Parse("0.1.1-gamma.12.87");
+            var v2 = SemVersion.Parse("0.1.1-gamma.12.88");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(-1, r);
+        }
+
+        [Fact]
+        public void CompareTest14()
+        {
+            var v1 = SemVersion.Parse("0.1.1-gamma.12.87");
+            var v2 = SemVersion.Parse("0.1.1-gamma.12.87.1");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(-1, r);
+        }
+
+        [Fact]
+        public void CompareTest15()
+        {
+            var v1 = SemVersion.Parse("0.1.1-gamma.12.87.99");
+            var v2 = SemVersion.Parse("0.1.1-gamma.12.87.X");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(-1, r);
+        }
+
+        [Fact]
+        public void CompareTest16()
+        {
+            var v1 = SemVersion.Parse("0.1.1-gamma.12.87");
+            var v2 = SemVersion.Parse("0.1.1-gamma.12.87.X");
+
+            var r = v1.CompareTo(v2);
+            Assert.Equal(-1, r);
+        }
+
+        [Fact]
+        public void CompareNullTest()
+        {
+            var v1 = SemVersion.Parse("0.0.1+bu");
+            var r = v1.CompareTo(null);
+            Assert.Equal(1, r);
+        }
+
+        [Fact]
+        public void TestHashCode()
+        {
+            var v1 = SemVersion.Parse("1.0.0-1+b");
+            var v2 = SemVersion.Parse("1.0.0-1+c");
+
+            var h1 = v1.GetHashCode();
+            var h2 = v2.GetHashCode();
+
+            Assert.NotEqual(h1, h2);
+        }
+
+        [Fact]
+        public void TestStringConversion()
+        {
+            SemVersion v = "1.0.0";
+            Assert.Equal(1, v.Major);
+        }
+
+        [Fact]
+        public void TestUntypedCompareTo()
+        {
+            var v1 = new SemVersion(1);
+            var c = v1.CompareTo((object)v1);
+
+            Assert.Equal(0, c);
+        }
+
+        [Fact]
+        public void StaticEqualsTest1()
+        {
+            var v1 = new SemVersion(1, 2, 3);
+            var v2 = new SemVersion(1, 2, 3);
+
+            var r = SemVersion.Equals(v1, v2);
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void StaticEqualsTest2()
+        {
+            var r = SemVersion.Equals(null, null);
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void StaticEqualsTest3()
+        {
+            var v1 = new SemVersion(1);
+
+            var r = SemVersion.Equals(v1, null);
+            Assert.False(r);
+        }
+
+        [Fact]
+        public void StaticCompareTest1()
+        {
+            var v1 = new SemVersion(1);
+            var v2 = new SemVersion(2);
+
+            var r = SemVersion.Compare(v1, v2);
+            Assert.Equal(-1, r);
+        }
+
+        [Fact]
+        public void StaticCompareTest2()
+        {
+            var v1 = new SemVersion(1);
+
+            var r = SemVersion.Compare(v1, null);
+            Assert.Equal(1, r);
+        }
+
+        [Fact]
+        public void StaticCompareTest3()
+        {
+            var v1 = new SemVersion(1);
+
+            var r = SemVersion.Compare(null, v1);
+            Assert.Equal(-1, r);
+        }
+
+        [Fact]
+        public void StaticCompareTest4()
+        {
+            var r = SemVersion.Compare(null, null);
+            Assert.Equal(0, r);
+        }
+
+        [Fact]
+        public void EqualsOperatorTest()
+        {
+            var v1 = new SemVersion(1);
+            var v2 = new SemVersion(1);
+
+            var r = v1 == v2;
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void UnequalOperatorTest()
+        {
+            var v1 = new SemVersion(1);
+            var v2 = new SemVersion(2);
+
+            var r = v1 != v2;
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void GreaterOperatorTest()
+        {
+            var v1 = new SemVersion(1);
+            var v2 = new SemVersion(2);
+
+            var r = v2 > v1;
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void GreaterOperatorTest2()
+        {
+            var v1 = new SemVersion(1, 0, 0, "alpha");
+            var v2 = new SemVersion(1, 0, 0, "rc");
+
+            var r = v2 > v1;
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void GreaterOperatorTest3()
+        {
+            var v1 = new SemVersion(1, 0, 0, "-ci.1");
+            var v2 = new SemVersion(1, 0, 0, "alpha");
+
+            var r = v2 > v1;
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void GreaterOrEqualOperatorTest1()
+        {
+            var v1 = new SemVersion(1);
+            var v2 = new SemVersion(1);
+
+            var r = v1 >= v2;
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void GreaterOrEqualOperatorTest2()
+        {
+            var v1 = new SemVersion(2);
+            var v2 = new SemVersion(1);
+
+            var r = v1 >= v2;
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void LessOperatorTest()
+        {
+            var v1 = new SemVersion(1);
+            var v2 = new SemVersion(2);
+
+            var r = v1 < v2;
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void LessOperatorTest2()
+        {
+            var v1 = new SemVersion(1, 0, 0, "alpha");
+            var v2 = new SemVersion(1, 0, 0, "rc");
+
+            var r = v1 < v2;
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void LessOperatorTest3()
+        {
+            var v1 = new SemVersion(1, 0, 0, "-ci.1");
+            var v2 = new SemVersion(1, 0, 0, "alpha");
+
+            var r = v1 < v2;
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void LessOrEqualOperatorTest1()
+        {
+            var v1 = new SemVersion(1);
+            var v2 = new SemVersion(1);
+
+            var r = v1 <= v2;
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void LessOrEqualOperatorTest2()
+        {
+            var v1 = new SemVersion(1);
+            var v2 = new SemVersion(2);
+
+            var r = v1 <= v2;
+            Assert.True(r);
+        }
+
+        [Fact]
+        public void TestChangeMajor()
+        {
+            var v1 = new SemVersion(1, 2, 3, "alpha", "dev");
+            var v2 = v1.Change(major: 5);
+
+            Assert.Equal(5, v2.Major);
+            Assert.Equal(2, v2.Minor);
+            Assert.Equal(3, v2.Patch);
+            Assert.Equal("alpha", v2.Prerelease);
+            Assert.Equal("dev", v2.Build);
+        }
+
+        [Fact]
+        public void TestChangeMinor()
+        {
+            var v1 = new SemVersion(1, 2, 3, "alpha", "dev");
+            var v2 = v1.Change(minor: 5);
+
+            Assert.Equal(1, v2.Major);
+            Assert.Equal(5, v2.Minor);
+            Assert.Equal(3, v2.Patch);
+            Assert.Equal("alpha", v2.Prerelease);
+            Assert.Equal("dev", v2.Build);
+        }
+
+        [Fact]
+        public void TestChangePatch()
+        {
+            var v1 = new SemVersion(1, 2, 3, "alpha", "dev");
+            var v2 = v1.Change(patch: 5);
+
+            Assert.Equal(1, v2.Major);
+            Assert.Equal(2, v2.Minor);
+            Assert.Equal(5, v2.Patch);
+            Assert.Equal("alpha", v2.Prerelease);
+            Assert.Equal("dev", v2.Build);
+        }
+
+        [Fact]
+        public void TestChangePrerelease()
+        {
+            var v1 = new SemVersion(1, 2, 3, "alpha", "dev");
+            var v2 = v1.Change(prerelease: "beta");
+
+            Assert.Equal(1, v2.Major);
+            Assert.Equal(2, v2.Minor);
+            Assert.Equal(3, v2.Patch);
+            Assert.Equal("beta", v2.Prerelease);
+            Assert.Equal("dev", v2.Build);
+        }
+
+#if !NETSTANDARD
+        [Fact]
+        public void TestSerialization()
+        {
+            var semVer = new SemVersion(1, 2, 3, "alpha", "dev");
+            SemVersion semVerSerializedDeserialized;
+            using (var ms = new MemoryStream())
+            {
+                var bf = new BinaryFormatter();
+                bf.Serialize(ms, semVer);
+                ms.Position = 0;
+                semVerSerializedDeserialized = (SemVersion) bf.Deserialize(ms);
+            }
+            Assert.Equal(semVer, semVerSerializedDeserialized);
+        }
+#endif
+    }
+}
\ No newline at end of file
diff --git a/test/Semver.Test/Semver.Test.xproj b/test/Semver.Test/Semver.Test.xproj
new file mode 100644
index 0000000..469a42d
--- /dev/null
+++ b/test/Semver.Test/Semver.Test.xproj
@@ -0,0 +1,21 @@
+
+
+  
+    14.0
+    $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+  
+  
+  
+    da03e4c4-cb6c-447b-b617-15b5689e9029
+    Semver.Test
+    .\obj
+    .\bin\
+  
+  
+    2.0
+  
+  
+    
+  
+  
+
\ No newline at end of file
diff --git a/test/Semver.Test/project.json b/test/Semver.Test/project.json
new file mode 100644
index 0000000..5ecec7c
--- /dev/null
+++ b/test/Semver.Test/project.json
@@ -0,0 +1,44 @@
+{
+    "testRunner": "xunit",
+    "buildOptions": {
+        "debugType": "portable",
+        "warningsAsErrors": true,
+        "copyToOutput": {
+            "include": [ "xunit.runner.json" ]
+        }
+    },
+    "dependencies": {
+        "dotnet-test-xunit": "2.2.0-preview2-build1029",
+        "Semver": {
+            "target": "project"
+        },
+        "xunit": "2.2.0-beta2-build3300",
+        "xunit.extensibility.core": "2.2.0-beta2-build3300",
+        "xunit.extensibility.execution": "2.2.0-beta2-build3300",
+        "xunit.runner.visualstudio": "2.2.0-beta2-build1149"
+    },
+    "frameworks": {
+        "netcoreapp1.0": {
+            "buildOptions": {
+                "define": [ "NETSTANDARD", "NETSTANDARD1_5" ]
+            },
+            "dependencies": {
+                "Microsoft.NETCore.App": {
+                    "type": "platform",
+                    "version": "1.0.0"
+                },
+                "System.Runtime": "4.1.0" 
+            }
+        },
+        "NET46": {
+            "buildOptions": {
+                "define": [ "NET46" ]
+            },
+            "frameworkAssemblies": {
+                "System.Runtime": {
+                    "type": "build"
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/test/Semver.Test/xunit.runner.json b/test/Semver.Test/xunit.runner.json
new file mode 100644
index 0000000..1b40892
--- /dev/null
+++ b/test/Semver.Test/xunit.runner.json
@@ -0,0 +1,7 @@
+{
+    "diagnosticMessages": true,
+    "maxParallelThreads": 1,
+    "methodDisplay": "method",
+    "parallelizeAssembly": false,
+    "parallelizetestcollections": false
+}