From 3d1d7f8bc49b0cf009657571b3db05e499db681f Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 17 Nov 2019 11:52:42 +0000 Subject: [PATCH 01/53] enable using github actions for building + publish to github package repository --- .github/workflows/build-and-test.yml | 116 ++++++++++++++++++ .gitignore | 2 + Directory.Build.props | 2 +- build.ps1 | 100 +++++++++++++-- run-tests.ps1 | 7 +- src/ImageSharp/ImageSharp.csproj | 5 +- tests/CodeCoverage/CodeCoverage.ps1 | 11 ++ .../ImageSharp.Benchmarks.csproj | 5 +- .../ImageSharp.Sandbox46.csproj | 7 +- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 5 +- 10 files changed, 238 insertions(+), 22 deletions(-) create mode 100644 .github/workflows/build-and-test.yml create mode 100644 tests/CodeCoverage/CodeCoverage.ps1 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 0000000000..b4a194bc58 --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,116 @@ +name: Build + +on: + push: + branches: + - master + tags: + - 'v*' + pull_request: + branches: + - master + +jobs: + Coverage: + runs-on: windows-latest + needs: [Build] + steps: + - uses: actions/checkout@v1 + + - name: Enable long file paths + run: git config --global core.longpaths true + + - name: Update submodules + run: git submodule -q update --init + + - name: Generate Test Coverage + shell: pwsh + run: ./tests/CodeCoverage/CodeCoverage.ps1 + env: + CI : True + + - name: Update codecov + uses: iansu/codecov-action-node@v1.0.0 + with: + token: ${{secrets.CODECOV_TOKEN}} + file: "ImageSharp.Coverage.xml" + flags: unittests + + Build: + strategy: + matrix: + options: + - os : ubuntu-latest + framework: netcoreapp2.1 + is32Bit: False + - os : windows-latest + framework: netcoreapp2.1 + is32Bit: False + - os : windows-latest + framework: net472 + is32Bit: False + - os : windows-latest + framework: net472 + is32Bit: True + + runs-on: ${{ matrix.options.os }} + + steps: + - uses: actions/checkout@v1 + + - name: Enable long file paths + run: | + git config --global core.autocrlf false + git config --global core.longpaths true + + - name: Update submodules + run: git submodule -q update --init + + - name: Build + shell: pwsh + run: | + $DebugPreference = "Continue" + ./build.ps1 "${{matrix.options.framework}}" + + - name: Test + shell: pwsh + run: ./run-tests.ps1 "${{matrix.options.framework}}" "${{matrix.options.is32Bit}}" true + env: + CI : True + + Publish: + runs-on: windows-latest + needs: [Build] + if : github.event_name == 'push' + steps: + - uses: actions/checkout@v1 + + - name: Enable long file paths + run: git config --global core.longpaths true + + - name: Update submodules + run: git submodule -q update --init + + - name: Build + shell: pwsh + run: | + $DebugPreference = "Continue" + ./build.ps1 + + - name : install nuget + if: success() + uses: warrenbuckley/Setup-Nuget@v1 + + - name: Configure feed + if: success() + run: nuget.exe source Add -Name "GitHub" -Source "https://nuget.pkg.github.com/sixlabors/index.json" -UserName ${{github.actor}} -Password ${{ secrets.GITHUB_TOKEN }} + + - name: Publish to nightly feed - github + if: success() + run: nuget.exe push -Source "GitHub" .\artifacts\*.nupkg + + - name: Publish to nightly feed -myget + if: success() + run: nuget.exe push .\artifacts\*.nupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v2/package + + # todo if github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org \ No newline at end of file diff --git a/.gitignore b/.gitignore index d8f376a419..4007b1faba 100644 --- a/.gitignore +++ b/.gitignore @@ -221,3 +221,5 @@ artifacts/ # Tests **/Images/ActualOutput **/Images/ReferenceOutput +/tests/CodeCoverage/opencover.zip +/tests/CodeCoverage/OpenCover.4.6.519 diff --git a/Directory.Build.props b/Directory.Build.props index efe4cc9665..e865a83f85 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,7 +14,7 @@ $(MSBuildThisFileDirectory)artifacts/ $(ImageSharpProjectCategory)/$(MSBuildProjectName) - https://github.com/SixLabors/ImageSharp/ + https://github.com/SixLabors/ImageSharp/ diff --git a/build.ps1 b/build.ps1 index 215b551170..1bc7ff6cc1 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,20 +1,79 @@ +param( + [string]$targetFramework = 'ALL' +) # lets calulat the correct version here $fallbackVersion = "1.0.0"; $version = '' -$tagRegex = '^v?(\d+\.\d+\.\d+)(-([a-zA-Z]+)\.?(\d*))?$' +$tagRegex = '^v?(\d+\.\d+\.\d+)(?:-([a-zA-Z]+)\.?(\d*))?$' + +$skipFullFramework = 'false' + +# if we are trying to build only netcoreapp versions for testings then skip building the full framework targets +if("$targetFramework".StartsWith("netcoreapp")){ + $skipFullFramework = 'true' +} + +function ToBuildNumber { + param( $date ) + if("$date" -eq ""){ + $date = [System.DateTime]::Now + } + + if($date.GetType().fullname -ne 'System.DateTime'){ + $date = [System.DateTime]::Parse($date) + } + + + return $date.ToString("yyyyMMddhhmmss") +} + +# if($IsWindows){ +# $skipFullFramework = 'true' +# Write-Info "Building full framework targets - Running windows" +# }else{ +# if (Get-Command "mono" -ErrorAction SilentlyContinue) +# { +# Write-Info "Building full framework targets - mono installed" +# $skipFullFramework = 'true' +# } +# } # we are running on the build server $isVersionTag = $env:APPVEYOR_REPO_TAG_NAME -match $tagRegex +if($isVersionTag -eq $false){ + $isVersionTag = "$env:GITHUB_REF".replace("refs/tags/", "") -match $tagRegex + if($isVersionTag){ + Write-Debug "Github tagged build" + } +}else{ + Write-Debug "Appveyor tagged build" +} + +if($isVersionTag -eq $false){ + if( "$(git diff --stat)" -eq '') + { + Write-Debug "Clean repo" + if("$(git tag --list)" -ne "") { + Write-Debug "Has tags" + $tagData = (git describe --tags HEAD) + $isVersionTag = $tagData -match $tagRegex + Write-Debug $tagData + } + }else{ + Write-Debug "Dirty repo" + } +} + if($isVersionTag) { Write-Debug "Building commit tagged with a compatable version number" $version = $matches[1] - $postTag = $matches[3] - $count = $matches[4] + $postTag = $matches[2] + $count = $matches[3] Write-Debug "version number: ${version} post tag: ${postTag} count: ${count}" if("$postTag" -ne ""){ $version = "${version}-${postTag}" @@ -53,8 +112,23 @@ $isVersionTag = $env:APPVEYOR_REPO_TAG_NAME -match $tagRegex $buildNumber = $env:APPVEYOR_BUILD_NUMBER - # build number replacement is padded to 6 places - $buildNumber = "$buildNumber".Trim().Trim('0').PadLeft(6,"0"); + if("$buildNumber" -eq ""){ + # no counter availible in this environment + # let make one up based on time + + if( "$env:GITHUB_SHA" -ne ''){ + $buildNumber = ToBuildNumber (git show -s --format=%ci $env:GITHUB_SHA) + }elseif( "$(git diff --stat)" -eq ''){ + $buildNumber = ToBuildNumber (git show -s --format=%ci HEAD) + }else{ + $buildNumber = ToBuildNumber + } + $buildNumber = "$buildNumber".Trim().Trim('0').PadLeft(12,"0"); + }else{ + # build number replacement is padded to 6 places + $buildNumber = "$buildNumber".Trim().Trim('0').PadLeft(6,"0"); + } + if("$env:APPVEYOR_PULL_REQUEST_NUMBER" -ne ""){ Write-Debug "building a PR" @@ -77,7 +151,7 @@ $isVersionTag = $env:APPVEYOR_REPO_TAG_NAME -match $tagRegex $branch = $branch.Replace("/","-").ToLower() - if($branch.ToLower() -eq "master"){ + if($branch.ToLower() -eq "master" -or $branch.ToLower() -eq "head"){ $branch = "dev" } @@ -94,10 +168,16 @@ if("$env:APPVEYOR_API_URL" -ne ""){ } Write-Host "Building version '${version}'" -dotnet restore /p:packageversion=$version /p:DisableImplicitNuGetFallbackFolder=true +dotnet restore /p:packageversion=$version /p:DisableImplicitNuGetFallbackFolder=true /p:skipFullFramework=$skipFullFramework + +$repositoryUrl = "https://github.com/SixLabors/ImageSharp/" + +if("$env:GITHUB_REPOSITORY" -ne ""){ + $repositoryUrl = "https://github.com/$env:GITHUB_REPOSITORY" +} Write-Host "Building projects" -dotnet build -c Release /p:packageversion=$version +dotnet build -c Release /p:packageversion=$version /p:skipFullFramework=$skipFullFramework /p:RepositoryUrl=$repositoryUrl if ($LASTEXITCODE ){ Exit $LASTEXITCODE } @@ -115,8 +195,8 @@ if ($LASTEXITCODE ){ Exit $LASTEXITCODE } if ($LASTEXITCODE ){ Exit $LASTEXITCODE } Write-Host "Packaging projects" -dotnet pack ./src/ImageSharp/ -c Release --output ../../artifacts --no-build /p:packageversion=$version +dotnet pack ./src/ImageSharp/ -c Release --output "$PSScriptRoot/artifacts" --no-build /p:packageversion=$version /p:skipFullFramework=$skipFullFramework /p:RepositoryUrl=$repositoryUrl if ($LASTEXITCODE ){ Exit $LASTEXITCODE } -dotnet pack ./src/ImageSharp.Drawing/ -c Release --output ../../artifacts --no-build /p:packageversion=$version +dotnet pack ./src/ImageSharp.Drawing/ -c Release --output "$PSScriptRoot/artifacts" --no-build /p:packageversion=$version /p:skipFullFramework=$skipFullFramework /p:RepositoryUrl=$repositoryUrl if ($LASTEXITCODE ){ Exit $LASTEXITCODE } diff --git a/run-tests.ps1 b/run-tests.ps1 index 4aeaa14908..2d563c67e6 100644 --- a/run-tests.ps1 +++ b/run-tests.ps1 @@ -1,6 +1,7 @@ param( [string]$targetFramework, - [string]$is32Bit = "False" + [string]$is32Bit = "False", + [string]$skipCodeCov = $false ) if (!$targetFramework){ @@ -41,9 +42,9 @@ function CheckSubmoduleStatus() { } -if ( ($targetFramework -eq "netcoreapp2.1") -and ($env:CI -eq "True") -and ($is32Bit -ne "True")) { +if ( ($targetFramework -eq "netcoreapp2.1") -and ($env:CI -eq "True") -and ($is32Bit -ne "True") -and $skipCodeCov -ne $true) { # We execute CodeCoverage.cmd only for one specific job on CI (netcoreapp2.1 + 64bit ) - $testRunnerCmd = ".\tests\CodeCoverage\CodeCoverage.cmd" + $testRunnerCmd = "./tests/CodeCoverage/CodeCoverage.ps1" } elseif ($targetFramework -eq "mono") { $testDllPath = "$PSScriptRoot\tests\ImageSharp.Tests\bin\Release\net462\SixLabors.ImageSharp.Tests.dll" diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 86b0848663..e0d70193fe 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -1,4 +1,4 @@ - + @@ -10,7 +10,8 @@ $(packageversion) 0.0.1 - netcoreapp2.1;netstandard1.3;netstandard2.0;net472 + netcoreapp2.1;netstandard1.3;netstandard2.0 + $(TargetFrameworks);net472 true true diff --git a/tests/CodeCoverage/CodeCoverage.ps1 b/tests/CodeCoverage/CodeCoverage.ps1 new file mode 100644 index 0000000000..b7073998f9 --- /dev/null +++ b/tests/CodeCoverage/CodeCoverage.ps1 @@ -0,0 +1,11 @@ + +if((Test-Path("$PSScriptRoot\OpenCover.4.6.519")) -eq $false){ + Invoke-WebRequest https://www.nuget.org/api/v2/package/OpenCover/4.7.922 -OutFile "$PSScriptRoot\opencover.zip" + [IO.Compression.Zipfile]::ExtractToDirectory("$PSScriptRoot\opencover.zip","$PSScriptRoot\OpenCover.4.6.519") +} + +dotnet clean ImageSharp.sln -c Release + +& "$PSScriptRoot\OpenCover.4.6.519\tools\OpenCover.Console.exe" -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f netcoreapp2.1 /p:skipFullFramework=true /p:codecov=true" -register:user -threshold:10 -oldStyle -safemode:off -output:.\ImageSharp.Coverage.xml -hideskipped:All -returntargetcode -filter:"+[SixLabors.ImageSharp*]*" + +if ($LASTEXITCODE ){ Exit $LASTEXITCODE } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index a57d388a95..ee0b2985f0 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -1,11 +1,12 @@ - + ImageSharp.Benchmarks Exe SixLabors.ImageSharp.Benchmarks - netcoreapp2.1;net472 + netcoreapp2.1 + $(TargetFrameworks);net472 false false diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index fc94668e11..b0826dcbed 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -1,4 +1,4 @@ - + @@ -8,7 +8,9 @@ false SixLabors.ImageSharp.Sandbox46 win7-x64 - net472 + netcoreapp2.1 + $(TargetFrameworks);net472 + SixLabors.ImageSharp.Sandbox46.Program @@ -18,6 +20,7 @@ + diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 1ac5f8085a..3bd5f6af2d 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,8 +1,9 @@ - + - netcoreapp2.1;net462;net472 + netcoreapp2.1 + $(TargetFrameworks);net462;net472 True latest full From 6e2ba688c22b7b0a804777e2b0f4c8902c312c58 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Wed, 11 Dec 2019 09:58:15 +0000 Subject: [PATCH 02/53] stop appveyor publishing pacakges --- appveyor.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 2cc5182d39..07876c12f6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -57,13 +57,13 @@ after_test: - cmd: appveyor PushArtifact "artifacts\SixLabors.ImageSharp.%APPVEYOR_BUILD_VERSION%.nupkg" - cmd: appveyor PushArtifact "artifacts\SixLabors.ImageSharp.Drawing.%APPVEYOR_BUILD_VERSION%.nupkg" -deploy: - # MyGet Deployment for builds & releases - - provider: NuGet - server: https://www.myget.org/F/sixlabors/api/v2/package - symbol_server: https://www.myget.org/F/sixlabors/symbols/api/v2/package - api_key: - secure: V/lEHP0UeMWIpWd0fiNlY2IgbCnJKQlGdRksECdJbOBdaE20Fl0RNL7WyqHe02o4 - artifact: /.*\.nupkg/ - on: - branch: master \ No newline at end of file +# deploy: +# # MyGet Deployment for builds & releases +# - provider: NuGet +# server: https://www.myget.org/F/sixlabors/api/v2/package +# symbol_server: https://www.myget.org/F/sixlabors/symbols/api/v2/package +# api_key: +# secure: V/lEHP0UeMWIpWd0fiNlY2IgbCnJKQlGdRksECdJbOBdaE20Fl0RNL7WyqHe02o4 +# artifact: /.*\.nupkg/ +# on: +# branch: master \ No newline at end of file From b12dd699f58a0f3f20c50d599b13e4d67550e254 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 12:32:58 +1100 Subject: [PATCH 03/53] Use dotnet test --- .github/workflows/build-and-test.yml | 208 ++++++++---------- .github/workflows/build-and-test.yml.bak | 116 ++++++++++ .vscode/launch.json | 28 --- .vscode/tasks.json | 31 --- Directory.Build.targets | 27 +-- ImageSharp.sln | 26 +-- build.ps1 | 128 ++++------- build/icons/imagesharp-logo-128.png | Bin 7568 -> 0 bytes build/icons/imagesharp-logo-256.png | Bin 15413 -> 0 bytes build/icons/imagesharp-logo-32.png | Bin 1799 -> 0 bytes build/icons/imagesharp-logo-512.png | Bin 32534 -> 0 bytes build/icons/imagesharp-logo-64.png | Bin 3736 -> 0 bytes build/icons/imagesharp-logo.png | Bin 32534 -> 0 bytes build/icons/imagesharp-logo.svg | 1 - run-tests.ps1 | 146 ++++++------ src/ImageSharp/ImageSharp.csproj | 4 - tests/CodeCoverage/CodeCoverage.cmd | 4 +- tests/Directory.Build.props | 6 + .../ImageSharp.Benchmarks.csproj | 5 - .../ImageSharp.Sandbox46.csproj | 6 +- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 8 - 21 files changed, 344 insertions(+), 400 deletions(-) create mode 100644 .github/workflows/build-and-test.yml.bak delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/tasks.json delete mode 100644 build/icons/imagesharp-logo-128.png delete mode 100644 build/icons/imagesharp-logo-256.png delete mode 100644 build/icons/imagesharp-logo-32.png delete mode 100644 build/icons/imagesharp-logo-512.png delete mode 100644 build/icons/imagesharp-logo-64.png delete mode 100644 build/icons/imagesharp-logo.png delete mode 100644 build/icons/imagesharp-logo.svg diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index b4a194bc58..825c1f1cad 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -1,116 +1,98 @@ name: Build -on: - push: - branches: - - master - tags: - - 'v*' - pull_request: - branches: - - master - +on: + push: + branches: + - master + tags: + - "v*" + pull_request: + branches: + - master + jobs: - Coverage: - runs-on: windows-latest - needs: [Build] - steps: - - uses: actions/checkout@v1 - - - name: Enable long file paths - run: git config --global core.longpaths true - - - name: Update submodules - run: git submodule -q update --init - - - name: Generate Test Coverage - shell: pwsh - run: ./tests/CodeCoverage/CodeCoverage.ps1 - env: - CI : True - - - name: Update codecov - uses: iansu/codecov-action-node@v1.0.0 - with: - token: ${{secrets.CODECOV_TOKEN}} - file: "ImageSharp.Coverage.xml" - flags: unittests - - Build: - strategy: - matrix: - options: - - os : ubuntu-latest - framework: netcoreapp2.1 - is32Bit: False - - os : windows-latest - framework: netcoreapp2.1 - is32Bit: False - - os : windows-latest - framework: net472 - is32Bit: False - - os : windows-latest - framework: net472 - is32Bit: True - - runs-on: ${{ matrix.options.os }} - - steps: - - uses: actions/checkout@v1 - - - name: Enable long file paths - run: | - git config --global core.autocrlf false - git config --global core.longpaths true - - - name: Update submodules - run: git submodule -q update --init - - - name: Build - shell: pwsh - run: | - $DebugPreference = "Continue" - ./build.ps1 "${{matrix.options.framework}}" - - - name: Test - shell: pwsh - run: ./run-tests.ps1 "${{matrix.options.framework}}" "${{matrix.options.is32Bit}}" true - env: - CI : True - - Publish: - runs-on: windows-latest - needs: [Build] - if : github.event_name == 'push' - steps: - - uses: actions/checkout@v1 - - - name: Enable long file paths - run: git config --global core.longpaths true - - - name: Update submodules - run: git submodule -q update --init - - - name: Build - shell: pwsh - run: | - $DebugPreference = "Continue" - ./build.ps1 - - - name : install nuget - if: success() - uses: warrenbuckley/Setup-Nuget@v1 - - - name: Configure feed - if: success() - run: nuget.exe source Add -Name "GitHub" -Source "https://nuget.pkg.github.com/sixlabors/index.json" -UserName ${{github.actor}} -Password ${{ secrets.GITHUB_TOKEN }} - - - name: Publish to nightly feed - github - if: success() - run: nuget.exe push -Source "GitHub" .\artifacts\*.nupkg - - - name: Publish to nightly feed -myget - if: success() - run: nuget.exe push .\artifacts\*.nupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v2/package - - # todo if github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org \ No newline at end of file + Build: + strategy: + matrix: + opts: + - os: ubuntu-latest + framework: netcoreapp2.1 + runtime: linux-x64 + cover: False + - os: windows-latest + framework: netcoreapp2.1 + runtime: win-x64 + cover: True + - os: windows-latest + framework: net472 + runtime: win-x64 + cover: False + - os: windows-latest + framework: net472 + runtime: win-x86 + cover: False + + runs-on: ${{ matrix.opts.os }} + + steps: + - uses: actions/checkout@v1 + + - name: Install nuget + uses: NuGet/setup-nuget@v1 + + - name: Enable long file paths + run: | + git config --global core.autocrlf false + git config --global core.longpaths true + + - name: Update Submodules + run: git submodule -q update --init --recursive + + - name: Build + shell: pwsh + run: | + $DebugPreference = "Continue" + ./build.ps1 "${{matrix.opts.framework}}" + + - name: Test no Coverage + if: matrix.opts.cover != 'True' + run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opt.framework}}" -r "${{matrix.opt.runtime}}" --no-build --filter Sandbox + + - name: Test with Coverage + if: matrix.opts.cover == 'True' + run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opt.framework}}" -r "${{matrix.opt.runtime}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover + + - name: Update Codecov + uses: iansu/codecov-action-node@v1.0.0 + if: matrix.opts.cover == 'True' + with: + token: ${{secrets.CODECOV_TOKEN}} + file: "coverage.xml" + flags: unittests + + # Publish: + runs-on: windows-latest + needs: [Build] + if: github.event_name == 'push' + steps: + - uses: actions/checkout@v1 + + - name: install nuget + uses: NuGet/setup-nuget@v1 + + - name: Enable long file paths + run: git config --global core.longpaths true + + - name: Update submodules + run: git submodule -q update --init --recursive + + - name: Build + shell: pwsh + run: | + $DebugPreference = "Continue" + ./build.ps1 + + - name: Publish to nightly feed -myget + if: success() + run: nuget.exe push .\artifacts\*.nupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v2/package + # TODO: if github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org diff --git a/.github/workflows/build-and-test.yml.bak b/.github/workflows/build-and-test.yml.bak new file mode 100644 index 0000000000..7d7d2ad26b --- /dev/null +++ b/.github/workflows/build-and-test.yml.bak @@ -0,0 +1,116 @@ +name: Build + +on: + push: + branches: + - master + tags: + - "v*" + pull_request: + branches: + - master + +jobs: + Coverage: + runs-on: windows-latest + needs: [Build] + steps: + - uses: actions/checkout@v1 + + - name: Install nuget + uses: NuGet/setup-nuget@v1 + + - name: Enable long file paths + run: git config --global core.longpaths true + + - name: Update submodules + run: git submodule -q update --init --recursive + + - name: Generate Test Coverage + shell: pwsh + run: ./tests/CodeCoverage/CodeCoverage.ps1 + env: + CI: True + + - name: Update codecov + uses: iansu/codecov-action-node@v1.0.0 + with: + token: ${{secrets.CODECOV_TOKEN}} + file: "ImageSharp.Coverage.xml" + flags: unittests + + Build: + strategy: + matrix: + opts: + - os: ubuntu-latest + framework: netcoreapp2.1 + is32Bit: False + doCoverage: False + - os: windows-latest + framework: netcoreapp2.1 + is32Bit: False + doCoverage: True + - os: windows-latest + framework: net472 + is32Bit: False + doCoverage: False + - os: windows-latest + framework: net472 + is32Bit: True + doCoverage: False + + runs-on: ${{ matrix.opts.os }} + + steps: + - uses: actions/checkout@v1 + + - name: install nuget + uses: NuGet/setup-nuget@v1 + + - name: Enable long file paths + run: | + git config --global core.autocrlf false + git config --global core.longpaths true + + - name: Update submodules + run: git submodule -q update --init + + - name: Build + shell: pwsh + run: | + $DebugPreference = "Continue" + ./build.ps1 "${{matrix.opts.framework}}" + + - name: Test + shell: pwsh + run: ./run-tests.ps1 "${{ matrix.opts.os }}" "${{matrix.opts.framework}}" "${{matrix.opts.is32Bit}}" "${{matrix.opts.doCoverage}}" + env: + CI: True + + Publish: + runs-on: windows-latest + needs: [Build] + if: github.event_name == 'push' + steps: + - uses: actions/checkout@v1 + + - name: install nuget + uses: NuGet/setup-nuget@v1 + + - name: Enable long file paths + run: git config --global core.longpaths true + + - name: Update submodules + run: git submodule -q update --init --recursive + + - name: Build + shell: pwsh + run: | + $DebugPreference = "Continue" + ./build.ps1 + + - name: Publish to nightly feed -myget + if: success() + run: nuget.exe push .\artifacts\*.nupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v2/package + # TODO: if github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index c772e647ce..0000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - // Use IntelliSense to find out which attributes exist for C# debugging - // Use hover for the description of the existing attributes - // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md - "version": "0.2.0", - "configurations": [ - { - "name": ".NET Core Launch (console)", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceRoot}/tests/ImageSharp.Benchmarks/bin/Debug/netcoreapp2.0/ImageSharp.Benchmarks.dll", - "args": [], - "cwd": "${workspaceRoot}/samples/AvatarWithRoundedCorner", - // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window - "console": "internalConsole", - "stopAtEntry": false, - "internalConsoleOptions": "openOnSessionStart" - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach", - "processId": "${command:pickProcess}" - } - ] -} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 82aaa2f8d0..0000000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "0.1.0", - "command": "dotnet", - "isShellCommand": true, - "args": [], - "tasks": [ - { - "taskName": "build", - "args": [ "ImageSharp.sln" ], - "isBuildCommand": true, - "showOutput": "always", - "problemMatcher": "$msCompile" - }, - { - "taskName": "build benchmark", - "suppressTaskName": true, - "args": [ "build", "tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj", "-f", "netcoreapp2.0", "-c", "Release" ], - "showOutput": "always", - "problemMatcher": "$msCompile" - }, - { - "taskName": "test", - "args": ["tests/ImageSharp.Tests/ImageSharp.Tests.csproj", "-c", "release", "-f", "netcoreapp2.0"], - "isTestCommand": true, - "showOutput": "always", - "problemMatcher": "$msCompile" - } - ] -} \ No newline at end of file diff --git a/Directory.Build.targets b/Directory.Build.targets index f6523fee03..71dd9ab99a 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -15,33 +15,34 @@ $(DefineConstants);$(OS) - - - - - - - - + - - - + + - + + + + + + + + + + + - diff --git a/ImageSharp.sln b/ImageSharp.sln index 227512cd1f..6a80589d8f 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -36,25 +36,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEM .github\ISSUE_TEMPLATE\feature-request.md = .github\ISSUE_TEMPLATE\feature-request.md EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".vscode", ".vscode", "{0274D4CF-9932-47CC-8E89-54DC05B8F06E}" - ProjectSection(SolutionItems) = preProject - .vscode\launch.json = .vscode\launch.json - .vscode\tasks.json = .vscode\tasks.json - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{E919DF0B-2607-4462-8FC0-5C98FE50F8C9}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "icons", "icons", "{2B02E303-7CC6-4E15-97EE-DBE86B287553}" - ProjectSection(SolutionItems) = preProject - build\icons\imagesharp-logo-128.png = build\icons\imagesharp-logo-128.png - build\icons\imagesharp-logo-256.png = build\icons\imagesharp-logo-256.png - build\icons\imagesharp-logo-32.png = build\icons\imagesharp-logo-32.png - build\icons\imagesharp-logo-512.png = build\icons\imagesharp-logo-512.png - build\icons\imagesharp-logo-64.png = build\icons\imagesharp-logo-64.png - build\icons\imagesharp-logo.png = build\icons\imagesharp-logo.png - build\icons\imagesharp-logo.svg = build\icons\imagesharp-logo.svg - EndProjectSection -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{815C0625-CD3D-440F-9F80-2D83856AB7AE}" ProjectSection(SolutionItems) = preProject src\Directory.Build.props = src\Directory.Build.props @@ -354,6 +335,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Benchmarks", "te EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Sandbox46", "tests\ImageSharp.Sandbox46\ImageSharp.Sandbox46.csproj", "{561B880A-D9EE-44EF-90F5-817C54A9D9AB}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{C0D7754B-5277-438E-ABEB-2BA34401B5A7}" + ProjectSection(SolutionItems) = preProject + .github\workflows\build-and-test.yml = .github\workflows\build-and-test.yml + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -418,7 +404,6 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {FBE8C1AD-5AEC-4514-9B64-091D8E145865} = {1799C43E-5C54-4A8F-8D64-B1475241DB0D} - {2B02E303-7CC6-4E15-97EE-DBE86B287553} = {E919DF0B-2607-4462-8FC0-5C98FE50F8C9} {2AA31A1F-142C-43F4-8687-09ABCA4B3A26} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} {D4C5EC58-F8E6-4636-B9EE-C99D2578E5C6} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {FA55F5DE-11A6-487D-ABA4-BC93A02717DD} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} @@ -438,6 +423,7 @@ Global {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {2BF743D8-2A06-412D-96D7-F448F00C5EA5} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {561B880A-D9EE-44EF-90F5-817C54A9D9AB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} + {C0D7754B-5277-438E-ABEB-2BA34401B5A7} = {1799C43E-5C54-4A8F-8D64-B1475241DB0D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5F8B9D1F-CD8B-4CC5-8216-D531E25BD795} diff --git a/build.ps1 b/build.ps1 index e726fc30f9..e2c62c3d37 100644 --- a/build.ps1 +++ b/build.ps1 @@ -2,7 +2,7 @@ param( [string]$targetFramework = 'ALL' ) -# lets calulat the correct version here +# Lets calculate the correct version here $fallbackVersion = "1.0.0"; $version = '' @@ -10,13 +10,14 @@ $tagRegex = '^v?(\d+\.\d+\.\d+)(?:-([a-zA-Z]+)\.?(\d*))?$' $skipFullFramework = 'false' -# if we are trying to build only netcoreapp versions for testings then skip building the full framework targets +# If we are trying to build only netcoreapp versions for testings then skip building the full framework targets if ("$targetFramework".StartsWith("netcoreapp")) { $skipFullFramework = 'true' } function ToBuildNumber { param( $date ) + if ("$date" -eq "") { $date = [System.DateTime]::Now } @@ -25,32 +26,14 @@ function ToBuildNumber { $date = [System.DateTime]::Parse($date) } - return $date.ToString("yyyyMMddhhmmss") } -# if($IsWindows){ -# $skipFullFramework = 'true' -# Write-Info "Building full framework targets - Running windows" -# }else{ -# if (Get-Command "mono" -ErrorAction SilentlyContinue) -# { -# Write-Info "Building full framework targets - mono installed" -# $skipFullFramework = 'true' -# } -# } +# We are running on the build server +$isVersionTag = "$env:GITHUB_REF".replace("refs/tags/", "") -match $tagRegex -# we are running on the build server -$isVersionTag = $env:APPVEYOR_REPO_TAG_NAME -match $tagRegex - -if ($isVersionTag -eq $false) { - $isVersionTag = "$env:GITHUB_REF".replace("refs/tags/", "") -match $tagRegex - if ($isVersionTag) { - Write-Debug "Github tagged build" - } -} -else { - Write-Debug "Appveyor tagged build" +if ($isVersionTag) { + Write-Debug "Github tagged build" } if ($isVersionTag -eq $false) { @@ -75,13 +58,16 @@ if ($isVersionTag) { $version = $matches[1] $postTag = $matches[2] $count = $matches[3] - Write-Debug "version number: ${version} post tag: ${postTag} count: ${count}" + + Write-Debug "Version number: ${version} post tag: ${postTag} count: ${count}" + if ("$postTag" -ne "") { $version = "${version}-${postTag}" } + if ("$count" -ne "") { - # for consistancy with previous releases we pad the counter to only 4 places - $padded = $count.Trim().Trim('0').PadLeft(4, "0"); + # For consistancy with previous releases we pad the counter to only 4 places + $padded = $count.Trim().PadLeft(4, "0"); Write-Debug "count '$count', padded '${padded}'" $version = "${version}${padded}" @@ -94,10 +80,10 @@ else { $list = $lastTag.Split("`n") foreach ($tag in $list) { - Write-Debug "testing ${tag}" + Write-Debug "Testing ${tag}" $tag = $tag.Trim(); if ($tag -match $tagRegex) { - Write-Debug "matched ${tag}" + Write-Debug "Matched ${tag}" $version = $matches[1]; break; } @@ -112,71 +98,43 @@ else { Write-Debug "Discovered base version from tags '${version}'" } - $buildNumber = $env:APPVEYOR_BUILD_NUMBER + # Create a build number based on the current time. + $buildNumber = "" - if ("$buildNumber" -eq "") { - # no counter availible in this environment - # let make one up based on time - - if ( "$env:GITHUB_SHA" -ne '') { - $buildNumber = ToBuildNumber (git show -s --format=%ci $env:GITHUB_SHA) - } - elseif ( "$(git diff --stat)" -eq '') { - $buildNumber = ToBuildNumber (git show -s --format=%ci HEAD) - } - else { - $buildNumber = ToBuildNumber - } - $buildNumber = "$buildNumber".Trim().Trim('0').PadLeft(12, "0"); + if ( "$env:GITHUB_SHA" -ne '') { + $buildNumber = ToBuildNumber (git show -s --format=%ci $env:GITHUB_SHA) } - else { - # build number replacement is padded to 6 places - $buildNumber = "$buildNumber".Trim().Trim('0').PadLeft(6, "0"); - } - - if ("$env:APPVEYOR_PULL_REQUEST_NUMBER" -ne "") { - Write-Debug "building a PR" - - $prNumber = "$env:APPVEYOR_PULL_REQUEST_NUMBER".Trim().Trim('0').PadLeft(5, "0"); - # this is a PR - $version = "${version}-PullRequest${prNumber}${buildNumber}"; + elseif ( "$(git diff --stat)" -eq '') { + $buildNumber = ToBuildNumber (git show -s --format=%ci HEAD) } else { - Write-Debug "building a branch commit" + $buildNumber = ToBuildNumber + } - # this is a general branch commit - $branch = $env:APPVEYOR_REPO_BRANCH + $buildNumber = "$buildNumber".Trim().PadLeft(12, "0"); - if ("$branch" -eq "") { - $branch = ((git rev-parse --abbrev-ref HEAD) | Out-String).Trim() + Write-Debug "Building a branch commit" - if ("$branch" -eq "") { - $branch = "unknown" - } - } + # This is a general branch commit + $branch = ((git rev-parse --abbrev-ref HEAD) | Out-String).Trim() - $branch = $branch.Replace("/", "-").ToLower() + if ("$branch" -eq "") { + $branch = "unknown" + } - if ($branch.ToLower() -eq "master" -or $branch.ToLower() -eq "head") { - $branch = "dev" - } + $branch = $branch.Replace("/", "-").ToLower() - $version = "${version}-${branch}${buildNumber}"; + if ($branch.ToLower() -eq "master" -or $branch.ToLower() -eq "head") { + $branch = "dev" } -} -if ("$env:APPVEYOR_API_URL" -ne "") { - # update appveyor build number for this build - Invoke-RestMethod -Method "PUT" ` - -Uri "${env:APPVEYOR_API_URL}api/build" ` - -Body "{version:'${version}'}" ` - -ContentType "application/json" + $version = "${version}-${branch}${buildNumber}"; } Write-Host "Building version '${version}'" dotnet restore /p:packageversion=$version /p:DisableImplicitNuGetFallbackFolder=true /p:skipFullFramework=$skipFullFramework -$repositoryUrl = "https://github.com/SixLabors/ImageSharp/" +$repositoryUrl = "https://github.com/SixLabors/" if ("$env:GITHUB_REPOSITORY" -ne "") { $repositoryUrl = "https://github.com/$env:GITHUB_REPOSITORY" @@ -187,19 +145,7 @@ dotnet build -c Release /p:packageversion=$version /p:skipFullFramework=$skipFul if ($LASTEXITCODE ) { Exit $LASTEXITCODE } -# -# TODO: DO WE NEED TO RUN TESTS IMPLICITLY? -# -# if ( $env:CI -ne "True") { -# cd ./tests/ImageSharp.Tests/ -# dotnet xunit -nobuild -c Release -f netcoreapp2.0 --fx-version 2.0.0 -# ./RunExtendedTests.cmd -# cd ../.. -# } -# - -if ($LASTEXITCODE ) { Exit $LASTEXITCODE } - Write-Host "Packaging projects" -dotnet pack ./src/ImageSharp/ -c Release --output "$PSScriptRoot/artifacts" --no-build /p:packageversion=$version /p:skipFullFramework=$skipFullFramework /p:RepositoryUrl=$repositoryUrl + +dotnet pack -c Release --output "$PSScriptRoot/artifacts" --no-build /p:packageversion=$version /p:skipFullFramework=$skipFullFramework /p:RepositoryUrl=$repositoryUrl if ($LASTEXITCODE ) { Exit $LASTEXITCODE } diff --git a/build/icons/imagesharp-logo-128.png b/build/icons/imagesharp-logo-128.png deleted file mode 100644 index b60966e042a05971f7a607729c22854981ac21b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7568 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 I*pI;f0qB`0F8}}l diff --git a/build/icons/imagesharp-logo-32.png b/build/icons/imagesharp-logo-32.png deleted file mode 100644 index 48e9ab718c125b76abbd86c4c153f387e5e7bdce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1799 zcmV+i2l)7jP)A6&&5oS_O@G^Hyj&y&_J@5Cv?>XOgNB9<@w?ie4p-hp75kjH_0Tfz+i&l@l zK_)jxz73~mMA55-0Vm7*Jg_RG|G2FiAq`R5#5__R!Jj-dSJe)L6jlZa z4g}s7k-epRpP1+w)ATpslXT(==S*H`mx7@D5tk_)5c514vA0qhm~*iFIe`^Gj`5gR z0W3|{0QOK8+m6{i-R(_LyQfyFR2apiU6w(8TX1pZeFTkUu9DJ`045F}=Z2nVH#v zjFEg?2_`6(osBUA&=c@i4G;$qBl>6R>Ws&+HmmB5j`kbPU7f7~)CmG{OOw?AqoW<` zfe?V>IGMM@-Q4QvN^1IMOlkK>CET3?`FRRZ>D-c&D`iY$XGh1)I@^vF4)C`leyjNN|eKORNPTwTJ1-s|0)MX0`h#`+~z@|42* zG1KV;$UFFo4Kz;Ue%?5<1E9T{_zIMD)jhFj>qasDGncc5Pbkmy?qlsiQB+b zN6kCbv7n$NxgX$apLqEIswchTy!*n9OF!8?aauF*41j~ui=#Per9SeZ&4@~#TYH?i z)4!1BmB{?(0WPs^^u5Xl)l=TYj$C!D8sP2?Xgf}i8$UwOsN%Q+xVM=EwiRuCblg4j zsiW$~g|8I0-(?We?goR=6btB1(qj!23i{&q@9!+Q6i2iko=SBGfGv@&z}Em7SeC20 z(q>R;a?4wzyyFJpg_R|B^UG|NO3;t#>x2Uw@@lfOv~-R4@zAn`Yp-4FMRX%TwlP_5 z{Gwcz1s^O5Saz?!|D~-?^2D;kovyA2#6{lB0hrFOIsqP^vV0w|k%SZ<{pS7F`bpDI zPV;8Wb-km6wE{4D$$r;`7`7wA^+xxDHPY5i!#j3)QRTR}owxwxBD{I@^4?!JJn&Gd zV>kh%oCe33VgnF0=4ebzTdK$J%WU=eeV_U~PTSDO>v7JKmzN0;kK0>-TmY1p%0n;y zsPyYE8-QId)i*ry)#(ccKpgptYlR3Vf5wAYzAuO8^kqJME&SNjWwQ}^q5rMV6S$e5 zHE|25SRPL;&@p@{e}y}jQPehj0N2HcSUxjh=0heszX6f9I|L`~<5}+m7)Ra!EWw0> z{_#Eefx-er9$htS%g-KeJar3X^AN_Xxt_?LzViBAFR6dVi2l>P6aCJeq((c=INdF4 z>?2!FJUe6E%7n(Z2CVD}8J^6c-maf%<>KO)KwL8~u`ws!%PsJu8 z>mvIqUSBc$catQk=YZ@~xWSAj;OJJ4D3sRKO4ym?*t&Juil?H zs7TAAMIWR*3(|f@2bR=VsOTSnLI6dci0!X9vV7)mA2CKg8)-a9qbN0d&eVS7hDiJ0 zFmj-xKAM$XjLKS7eLc3n;s~f%mi%c1@slE2*{g|J>BJeig5gnBTvyXjr-y2|+?oQc}9RC6*BBlunUGK&1N{ z{@?q)To)|t&OCGGJSXmRpEE?NsmS8vP~rdpfG;m6r2zm?@K-2+g#o^tc>lZtU(np& z$ZKJNU;bE@5#Zn0E^>PA06@_5@C`|1BcKA`q(DgPA~c*Ecy5wS~X+-U2z|={M3Muf73XY#9=q7CeCHVo}+DP zPxL+i4_)@^yRjG}l-bI+euhOqqc~pgHdY+NO5>B=x1C9>i*JJKSR8l03|XpLZ>FC& z2i0|Y%1yAlkGO9R9pC!j%rbpGzUxD525gEPLZ9a+Xeh9NKUi<%gpe8ov_n;60%qQ- zAHNbAJPO=USLmOBiWdVG7+-z#Su~0zX$Co-xe-Nxu3--YrfJ*`x>X=~v+x z;V|;n!yrbCu~t|%h4>?JTu2Pwf6yk9Y*J(zxosU1!+IV&YHwE8BOdEeqQsOr#{Zij zZU;0!LADN1Q^4YJc%?+S#TCPB`kFhLV$Ay;1z}D%5RJ)&fqX_?-|-1JLsk>7zQD7O zvPvDsvoEE0V5zdh#b0VN5X#fIRKNxDU-!J`eAnyvUbsTji71h(z>R^!COaM359CZx zgw^x>eFEXdbD--LcKEd~*E65}Jy>J;;qKT?F}|9u{o*i?edO{q?a+#hSAi}SIL2p(A?r%qRgnrGnp(j zlEsEO=tzxgvrIC1ey7`r;e#W*D*^IjAUa_r-#4Mgh+3J^ekF+@M~fp;4pU9x(Toba z+lTUx-G8ys{JWG}`3IpNbnSnqcZMF?ZB=Tm?0icfU>mBMh|!F#kMUy&iN*ZOvfXyQ zC_QV%^H#0DKxXH;!UiP`MD6PjKLXl4{b{If${~}>J9N#mtiRpwDrQDZitom~BuEtc zul`XGxrq*DPeO*I51a~eTO?5WrA?lEM9~P+e7E>mph(S>gA+l#DFqLLL{9=<(SZYm zyq>8Yj`pA=9d?jxH&SOB{yrKF7Y1aQQ`apu@>k2F*Q#7kJ|;Qcl_K!+-BJUkGz7!E zVxO$Zy!R*QF@ai$o;~r-{ij&FFEnYlKD|F7kuYE-1kHwiq-gk@@;Vts)`SuS2&Yu9 zE~8M5nAOLX1}`^o>8Od!u6Kyomgk;k$QFl;69FW;58{)i;$q#9{1G8h-4I!}C6l#= zPd&~5{Kt9klWPb@t}P6SecgV-MD)bVVe3ck!9uI%%QTIpai};t&Y_@xS@q5vNdz`` zf&7+w@Nu)8{QmI-{mZErEFHl};g*Xe*lHu)ox1#&K$R6-?O!?n(ntXXY95Eez<-7P zn}a9;n0PRPi9|f~{sXwt>@nCumAC&wOW&lRpAU1KRe%+kx>XI z1qO76s?x9eng3kZ-Ae-v;3fT)ytA{L&RBP-Q_t8-imKSp@lS$&mV_X;BFZp7BzGKt zbgtg-Og*)bNIG_XMcfgp1b9IZIgedwD(+y;-Tf3 z8{eFLreX(7u6oOA!kbG_F+WC;VWp^)7of1B)}r;UhpT9!<+F!zPC@tpyK%C&YV;Z7}6cRN;)ud<_y^|^bR=7oc|ZZ z2c`PzNa=1$Mk;`sW9%jiyXl*^^l&9s3vB@<`3pd+|MntX3mtHLGx}evwRrsgd_rwF$Ihw)+Wl4Z-r#!*xAy*Qdmuq> zOa1Ff8)!a>p!w`CoNO5Z-TAeDYBR~bNIFc8qe-D9mEc~q^?tLVHfJbL=Ghhk7{RNJ zDa^*dvwQU?LuiLCbxm=Q*0OhFLa?POIP#E{rr`+tL#Nz(^=1iNz(cLo{RFNlux;7T%N94Z?2Gy}t(%2Hvf?z+q(F(m5Kj)%xF->e8?eYf zF7iiF?XS_x!pl|Vnfo7`XxzDDh;nA+CL5dS@;_-=%UDssRPW43M_$3LG!5Mn*CkKVuWNDvZK0?E z{u8%6%Sr4BmY3Y(NBNp2kYn~8_FGHf=G*sp`wu!!v+Oi7=oTDJB43+M|+-#50ne_`)X>y3?|{$u;^V1gKnBpY3P`S<3(c&GU`8kEjg z=3^GY`$sIrZAwB?Ouv+aT5G7H4-=w`E`uw``<#;yz_Sn^;~r%t!}WqCFTfCE|0Xfr zS~w;xPZD9}t!YWrHFXI?J%`^t8`r&SyjWwQO(w`)-^LPuqQI{t*!j}>8BA8*M*Rbl zYX8%`FsS7J^!fJ3>bQBaMhe7?O#w0Vqne2gsz!zP>UR@F$k$z`n!UoOpMzw2Z&ZYX zNbpYDr{WFiGjiAnj)$?lwg~^+!kgeq_c|SQ{wzN>rSo7c_YW5{%_QT-Pvf*HSOD-6 zM{<8+MsP$vcE0+Gh*rYaNmg~GX~m{v&G>F|B9zjh-cqy4IU%2LUI$<`Yjyvkt)IOT zC2wvCl@EIian}7_|Kkz5GvW2sGtD53zhrstSZ2`7D)lDsiw~!+J6r?8zPNOGP3`_E z#91fVR%IPvDtXt(WkTFH66AVmh#ZX@p^qSMLP@vgTNBxRef>L5>JBz0Pk+YzLRMnX_H19jHx#Yk1(gb3qM&pXzp z=<3B%P~Xq0y?5uvM(zPL|0L7tAIVD1(WjCYMcbb#9;x_G>;UbA*-GH*BIY*&8v1_m z;Js6)5tTd3wabUHOz1(Q{${Oz8C1}AoM)hs#!rt0)&-W0`2>u_>`0I%Z$M@H@AHih zPtdn~vQ>I9F>+5wURY(-_B9vsD_hl+KygYrT~bPnzDsL|UEvf1=0%$DGf-AYwxD3J zFu5Ri&zdgCDm>P-S_STaDA!AL|HOs-ht(5fK%6 zxjSju89^q)jTwDZ9#Mts#~&io3m5^xaH@gAriyDkES~(@=Tl^8hGxk>MW1IdYIc9J z`%IITQMKi9N+xH_v98?CXwon!~XVb-zFRsIayD z0oT3K^A6UHLiaTL=OJSFywMgC2W#>)S8oZNV1?g5Mq%x|RyZZ;G?cC5dy&C7*-o$* zH6i%M{1Nf3XnWp`PzGHJ)rmZgz(W|PFa09HlLv~WdQZhtEMhDqRS=MNcSD2>{BKz3 zDuYTstCAQkL|GPq4#_Lsv?`vNfWinyQ%u)`T76_9w4r3Xbx3pNoj(IlQ+- z*M(^ySmaJ$Jc|~%cAh~^aQAQCIw{UIkTmh$18`@BKm*|*lUY-L{y^Q!DCNNd8de$^ z8aZ4fAkRyEr#>TJ3HvPt?jrtU9+5ZQ{L^w^mH0+OEPQW zbou~VsHWJZVp8=TmT5YOWookNHR4*8g`{*AEl-$${0YH-V*e%{%BZ5+jiv_TLg=2rO zs171n{XC(UFu)-srctvazw z9bFwn2r8=&{@3f9_v9p)Bi@jT0pKOV)MS!Q#g3k7jwZ%_`dA12)q5$rAveQ%!3L96 zv{7eWi2hm{X$r=#5)=J)c*~Be8VUDBF#_tKkLldHkARN|}~DC#)h{rN_)iLAnZ zVr(=F#6PU1e#i9R!%nvUpe$Z5$k32|G^s8(5>gNyBLcFT9gOhlT;AtA=M}FQ^yF&1 zaa0Jzoxj||=+X;OKM`Jf)kmujT$EMSS&I;39w;I5F}5+o@_G02B`p=$GXxuj1K{F}D^3{OlsnW4RxqA}!ig`A6M`>!4c~G{20JTmsoiSh6s+`+sfs8I$?4ib z=qwL~?0ogWg<*Bf(Cfg5?V&m602kiEH(N95NmjXSLBw%^wL;wBG|3otFzb6F7q-Od zSMpnZT8*~5)bNpnk*_sf)|;}sNh;Xu{hykZZ~+NFW;BL4g96qm+ zOcs2PO*FX=3cFnBhi>`tjv?$Q^TXGQj6mGg?gtNKj;>|Mub-OWemTXNarKPrUQ6ix zKMd|CoKLt9N*`ahF=jlQv4g+?75{(D0H)I+BELoYB26U6lYmH9Xy6VpndL7rnovjZ zE$)dyX`>pZxHAMz989>HrgzSuLQYAEjcDseXo0nu{=u&qK~Gj|e@lJ|Z1?DIl9-Tp zON|B4&}LKxx}IGh0yq!y@C4Fp)CjsL)>0-9J$H@sClilEkZuq{jaBACRB7Gs_sS>q z9_j!zv_vPL&%tje1QUd?EU<#pWA5yL_f+z1LGVNKz6>R#Y!8AZ8M6ZVa znBV)YJ%4$6HaLKxh}n-0h6i}e z;t2t)6tw%P$P}l-UkhuX5j{&%62U}K?@+VKZ4-w{V%+BN@m0$S$&cAhQLDAKIaC>F zT`(a*XjjyFo@wNu1D`_sPpbqx##YzD5_ZCy(;|-I{P6zcbMw9$_JxiM<;L zoe}a7Oo~%f(TcmtD$NE$GH~>QT-*_%9^ z%Jzm_e*tlxCW!5ea=L03`Lh?SOWWz#*^G>94TWUlwy{uwo7$YzJ;mFcSORnZDRL%` zOtMUjyRsqA^W2MCyLxj<^FbG2KM%Css=WH(8nm?b4>!*OEs_+tW-l|gEmR)V1Vjk{ z)0VF#S0~st#b@)v^zdMR9__EET8N%rFw?x;*E1CTh#XbeQWK1f`0IQ+SdjUY=IQe~ zkY>SX+iG|%gQB<&@QAZY7ykazDk5Q86mtwrd0NJDb4j;G4~Yk3kZF-KLvo`IN`7Z& ze)Q8KF9a=^6acJ6h3}o15FV)h=GrXL4dQmp-SGW?j{p{MqZdmdCOBZALMeQkjBbqm3X_E9Qjv0xZe-HRsO6{{&QbL|Cmr#6Nn!T{iVE zcXGYlnBac8z9b{=UP?ybwm7{K;_XQr^h!EA*I48_%571UQ!i-ADC7_=P%g~=ag==ZU$In6)=x9jY)volC2f=)iQ|T+R5B# zrmsT7KfDCTW`4*lBe-D#oA(^g%Wq>q?0BkJkdCuz2`=c27ovP0ulw3H6anv8SB7xy zrD}Fy9e6gIR8ka>y#1(+Zce2^S^W&s>jm0yx^?vT;55@8xMm?cqTtybTxtgz>&%yK zp)STZvf6Js1#q%|#D@tIqG{=O%LcLGR@ZcK6yNg0jT1+{x;;MnnDhOx{BvwP3%ApN zjznMSFI^HmG=IKjwZP8^01fG6U9nyOC0mB{#tTWMEZplnl#3U6bxLB*FtOgj z4a78be{GuGq;@5Tk*^$b{1MEoi(S#zA=8&I@uy!}z*^+lkog+3Cui!X{dPvRHzH83 z>$yuWuI|#)>)x8Oxytm*J@NFE-eFCdX1ilPWNRua2LoBX5H6CaVE-jA_fMr$e_c1$ zCJhh*;#&08m^u;fgOqC%=R|_Fu(4QRDA4ncVyJ1kn~B{*$utRlVl3uc*{2r;Yps2tm@|gVvY9zq_9Gr*qtj({m4e)#a&TR@nb;nIaaO5{Q@TgCD}chq;L#tzh3ki*7qX0g=GImv*02Yt==pnyVv3B z#!Ru1$_Q`ZkKk4oioyv69VPLV`5@B{-F1|Su#Z4t871&u!A89#nX*46SMh(Pm1XuD zZs=Hp``?(Z3^4%C-Tq#e9p0gtbIL*v7P6A)un=vG@?%UuWq}{eFNp@>wbH7gzgm&$ z_k<~$0s17we)V&zCN#p|)+)&q-*49)hBlhWZ>g<4A`5|*|$pO)-N>P66C1% zqz&9=IVV{O8Ub1&L06_0L!SYts}LDubmBfHlvZ8p%DtH;$qnS7iK;@8w@4hz+bi z^D_Jk0F%Q5#D;aHg5Y466N*DI{Tr+?6GtXY1i|i&TfyZ$KD4U|(@c@l zpY#G|*)t@uO$`;bJ}1P+N1i!d5r2^HW38n5Y%ABBCwZcyLJIuQ9;NMfQ@rzKR0x0P zu7bL7+&49Rks*0`!09Q!-=X-vPphNpW{^(Q7!-RB6>7grmVDiOX*j)Z34wE;z>(t< zf&^=|JXxt?CPGq$a(4TwkQ*5g6B340(Bn)ujDcc4n-F2uDw?IcGjnt>k4MC{4>Utf zr)!T@F}=ScVwdU0{*}mYoa5qa@Zi$Oc}YHSWQ;ir|-BY1cjtc zSI|sBTc7gkCC{6rv30hWu~&q~#Q4EK9*Qp=lowU{(c(uM**aCo&daxpSgyy`Px$aO z_rD|e7s}UUfe>|HKuk!})mK9LQ=z73n#ZcZ1>1z+l^Hoj4+yk#CcZFnIf2gUYaJb> zRYT+GsBG(0BAXM4xx3f!mA;zl#S84ZdS1pvhxdDVo!3j7%r#A89C(W_YD5&7Rbksy zpb`9=<&LCR7Oa&}Q?nVTUEThn`b2}g-UO3NPe@UWVz9=#!)>z?c2pcqkpz-qIRC5a zk)19YEa3fs%5h15743TMQJ&M)DaMxh^Cq8Nmb!|+6C z>=8(}H6yuVV|%Yo*^m0w)iOeTol<$Q6B)Cg?XczrFhE)v9s@|92?+p+#bo4M@l^Ld zikbx~8AcKNS%!5fSgQu6BIJWAya+TQJ#osIq;C2=u-uIJ!~exVhyaF+tqX~*JMKJ> zz#5N;kr;pe0f+G#2YSm~>^4tF<&B1tpO7G6`de97vWqUO7j7aM`EnXbjkMia<{G0d5E(3)_HO9*g=-pY*k_168y+Zp~H ziOhKieM}<5UBvay_UXCF8LKKcX;MYmWicW;6YU!i@x4rsr1AzkG=0(XE3UzCT;EB3 zq1Xx&4I1D*`pd#-VID9|K_qc06n>U_wh*t-(Cyl06wr_294Po^<2^4Y)*8^i{X>6V zGx_X%i?JcBQ#y>?kX%|_D+-dR+0fkIHK0yd=^Rfmks+=MO@DhipdjPJVHb|6m3~UGdz4sJ2c>IZ~w3L7&ETU(JOT(=49$BjFHf8UoML`&R(EG zLepN@vzMycQ5AZ$$%n{G54q3Q_}8l^O~Vh?Bl4!Qz@~PV#v1vaW9VVoU(X-;10Gv# ze=`wqz%-M{jlfa7(X`*3gTwueTAgfE?>KombPvYoU!J{mC)khRy z|KZ&^tJzqY4e1R@Pi=m#x5JXuUYy=&#--ssslN>czf#H{N>MQKv87_l|1C6a(}$4BzwdioM1*Xf!o?IU zumW2~6MFsM5%&ZYl4aS$J@n*0O0<54B~|CkK@mPG?+W7Vzvxm*m$bHt_X@Btxihj z{Zg?-%yy_k8(A4YLLZzuzP$WS>XxAH)pyv^B}|Uo4R(B3F!^P25Q9gPE;+H`ndU5o zbI*u3v4$NDks3qzyqz!;jd@To1ti7bcCMTHcRPNzj&OLG+=myUzQd`UZ7*o@9vu87 zw8pV|CWV5Arrg%qF?3<{_B`N+|Myvi<7^NxS7sQwu@PhXF1Z)x*g_P-31sTTWziBU z4c#tNK21^Gs|sPkvx$Hoyk3m=LP0>pyK?a*Kd)eEzkANs6rYus?fbTNv0Exzgn<@A zD#rmJoptAG+%M1|;F3n`?Q3T{mib5^GW0o8wr-6fbFH zT&J9drM07w2=rKT;-bq0)>f4w6Rp4x2rN1}bfB{Z7t%sQ-wD+oEixug92xI#Sfqmd z1Sy>YL>FmzPAXvebi&U;#3<-eLa1i%dIc1T(xTb+$Rnprc zml_v8I3MOCPQY5^+v;bubPyF#!Ztz{HwW|G5jkKhJ#?`t%a1EIO-9p#hLX~=8~bd% zJ+m%k$sUA_=E%O3w^*pOxu;X+mH&4ZK)kt^Zuw{Uz6ZXo>gJyg;zTOzY0gxJK<{L4 z2+-}ND2s)|@L{;bm`er(LZ#lv7N%wKBjYCF`1)Un<$fNDzoaO-<-dx($gEBT`zef* zEw!@gquFZv3-O+Ye-vJsdA-@fe0~Vu=8Nq=>&%H6eE{k7!u!tI;hle9OwbDvb#j$S ziyy>%DEPE*TeK2+c4ocve6A`iZ8+dT6M`VqLEoYY?!o*gmR6IQh=S?ZML$T9As6Gg zR$zrC&C(WQbw}Pk`A#f*BylUE8PMt>2cdl3lr05;(`T#*v zCAUCr$_2#5<)C<;zyv*8UPx9og~G8sMy|(;A#pb@_Oo&aTPY%liH2cvg)Hd_#wOSc zyLh%CFiYh8CZ`#{tQ*4W$Mii-sGVV|Ne)s~<@;56eOT}p{ZYT(=#ZG^L#n9vVGf20 z>vVfe*vkEpvbSdxFgzR~sBV*b;E5xeF?|}GF?n)bSN?;D1nOGhPb&LM`+Sv}WI#t* zJBebVUPU&zWBgh!*-|AOYWc5pR(~YgD<5nXfp~|ZnkU)j+$&0gFs4|kjUFWEztk#j z0q{02mVQ^GKhga3(NMlf9U0D4@6bZCQj7$w#9u!TLU_=!o3DRFM2AJsnXhl=}t z5U$d-#4sTCwWZ9&WE|Y3fsrN1SilKR?j^T{MQKepz8G#4$<$O4ADip; zn7IA-c{|X~$5-pyNro*jKguV$s#u#P!VABafdTj{y4~4{fsK1jc26ID19Q@@*JPkY zLz%Qxr*Je2rCl>6>K7RAOGHw8uTNuIqOx}@2d=_dvW{ydOmG47yV$J#Fm#?Ju|uo- zLqZScHM|xYlxN4hy|c4~;7#U>YpRIeY0p3Z*@j~um$N2%pixtq@SRF^%pW_Wp$4*)C0|QC7H;sp zliMNB__H?847sV)nc?r1w)pJ?0toLZDd1?IvGAI|X2QUJgd+pidpRNKrtBw+v#^Iq zMD8+fS_SfMC_>cUwyi#gs{G3>hqJ|!FLKc25EISDHADOE+Wz|?pG#kjyQAf8bLnMf z5#{KgW#G!ydM+1{IA#@eyVm5VgI$MMpX#vUg-2_yMKN8z)EP;JBJoVn17Q8(mBYT9 zKlQ*+Asw}1fJs+cJN3Dr?^Taim&dXFiibISrqEk!4{6ou43RZ|xF}NwV=_0)1OG+D zUMn!A=pgMcNV$9rHFY|*A!J;2s9fkLCPgL&3o)ZqOb9J)+I;;Cc)n2X{o4q<$HclA zPEk150om7wxWi@eI7PkCaOUTH>=OR4ZxV7By*=A*u1>Pe>H9Gh#cNFjR8Pisy^l>h z{d0qI=vL@%{Ei)ge|SRI9Sx(>ypRT%H$%BwOpv?d z*^j@OoVO6Eipf8@z37+3$vxu(7+W2f3ENhz>s3vHHVWp$wI2*J=qEYFxL`>)nG3wtX)#26oxkcIL4xAL~0+Hr> zn#R1pcCf@>{g(kYZrWUCO&gzc39~-x&EqvgSvb?Hl*l8U=H)dsQELKVMBJFnQ9V)#@SFL786)5q$ z_O`$SQx0Rs?q9CARopHfJ6aEoi@Jk9pMC@E2_rFyPdIupUPAjH80eKp(fl=64ZS2MEoIvYlV=2cFM!e&)DFwk)8hF9UV{P%-w z2z3x{UH9zxsy@4gpSikju@?X2H5<@Z53O}KvgH=#KTf?o&bN4|&K#wh3JZUb|IXpA z7Upa?-4BN7MMb`ATr}HXc$N&j))bNzHM0gGfrO&ps&;S*;6h|lH_OYacRnkZA;Cc}(hiJS!PuI`A&A({ z_B?k4Cmm|n8KG)IH*o5gaw~jOkT1%?0keI6D^4S4VImZe2(BQS`OE8f!T;8*oezmm z(Us>HAylr*I_$a#+_A}7>P|q;)RQ^ zBUBLEoA}{N@2RM~7&E5nl>yV0qpRN~zaFNKblv7_k*%YiDbGAY`|6{20Iz12gWOCde!7hE+k> zTngbOK^#O%JJu37K=8<1i{)argE3EOhV;|a*R@#aKY99YwD-jM=Z~; z;t{dHHl1fB7)KNPB%H>Ufz-CV1wHZA}~T$oUfFTI^& zCP8PLa;8t#Nyih_7ybm5GSBrSPmoSL4j+wh5xt z{3XgvlcSiVN02Qp6uz4#<(`&F6}Oe*D$!7pm#kYE~-#=&Rd&`53ht2rBU&k7t)sKhNU1L{fFl z#1=slPy|w|0E(^ar(DvP1PM*p zy{h+=`=O?RrI(7ywF*U1a_?%v6>5oOeAZg#rkGX1ZMSofzH$Zv*)zHohnfNpUwkz6 zar{NkDA?iD9jc#`kI(WWG4`wFP?5pwdbeyc3b5$vorAT9|C^xWixX$A(g1B*F(o0tnMKqQ~XQo{~Y+0mDcj*~mUE<2fA4WhOf{TYHs zV~e!`i_$q{n}wPUA&#+v??Ljplw6FZ)aC9uO|By80nAkKhuYlC>;%EglseL15>@>$ z!b8!=i{XijJPL!{w*H&^xh7*s|B$5(&G+2sya(5>iUr>soPuK(|KiTh`}+bPXEEa zommdhA+EwAULG%ji!^>&_~iSa=@auc2ni5>cV}9@aD&Z2DHzwAco81rIXtV z9`G8P2F1F2yHSQLJH|8-Dr{{l%nKnH^bR_%<_aJ*(C(H&Q>HFc^OGw+Ly4XzwAK5O zZ2|uFFWZFm)&6>R)D$oFgxgyXM=^cpJGW=RI&ECi8|BbN-(8o} zBbcz;!muX_aXVA;{r`!jrx}tg`BynXjQ}~?CQnVe^kshb)bE6OK}IJ9lj4SO zhx%3``hIN0ge5WR>g@wln~)1p>T@IA$YM0`A~9lm(B)!)FxuvPD2gENo03qdhQg_A z2M&NSJn9MG;BRT$EuI8xZ-2e8V`k_>b;7K49-A7gzeBFTGDUmaiY^{JrzLZ0Q0>^< zsQ7-CHh;+qpv-qanb1}cJXd(Hrcivh>ki@CioEO=7Z{1+8Zg0YM_8Y-)Pl7iWx!)k z?xXSvLEjJx#a@53mJ5BB#M&!EAO$N6OFa1^G(@`B7hbKa9UC?hUcE5<9}?yj?G%2` zQHr=XdXN-fYGviZ<3h~Adbs4m-t-JTTeaH^=Y${_tU+}DcYxLkF3`pDWL@nOd&^eJ zy#ON@)ltG*fgtlPo`)e2r4=g8R9{JuTUNl=%ECdG6slwr7~PSHMysRuuY2WN{NY?{ zQY31{4*s?fm7boGo1LJ6Iavrr)szvp;^g!Md@J$oR0l(2%$MK{Q-YtY=v);Uudwka zxWS=usw*u3K3>=c9w*Hn@*Z`&@ zwDCVA>#q%o8Us9S96&@iF(ApYl=5!j7s}Cnlg4M^2W$TE|8^<((mJvM+kdi%VwPpR zK|{f(*b5y9N!juKSo>VUfxK9R=KAg(bY?Z4P8o|@Wa%~Drbj#9z{%z|>2XA*BWr$w zs_$E{RT1EZj+JlxUfpftl*aTNDd?0{(&{*(r{VLGs58teh~}>=!;@bNuZZnd<~0>q zXirOksV8+Fqh17V?L_Xi%s^*+|aoyJP?cWGj8~rpfN$94-EO3-*Ex57je?qa?C;~ zqoA8ZORAT_^Ykt!ug)=nyS4ER{%5$uuqQ?aEcwvi+2~07@$}`_DjQGuqO~Mz_z6W0 zA{I7{|9E6BGrXg3=paD#U)57YF)P0zBW3`t#gJgW+JJQQj4|S$iBLS+;_`mY;Ly2B z)LWWe*F56~Glhkgag1AZ1;rF2vPL&~6E#?iK)JZS4t%5=uxYIXw%aDKa=g4r3dM4g z{1}n@dM$<@=Gqt(XEYRwQNr5+OLL<`D?_MXfuZVmuKE+(-W~asV%Dgeqek<}o2e+J z+vPQoN=HuzuPinK0^QR_h8@ z4^l$y5$BTmZz_I3S1*`V*;M8W?o2;wHWvmM;4V%F?zDTW%%U%roa#Z!79)h=u|3=G0=TfF_`rSv-PUtL7#HynPb7dOlK%RQgv}WCt7C3# zkc0A$3!6KGt5_>`x7t1Ha;R8`c-y$6>v>S#?m~PC)!4NsF~iP|bAZi$tb-M05e*f? zIk31j>_>iaJd1PgofCYLc;`o0TEafq23OjG#(hbj!|LLE5%OcO>cR_cpm^o0#%0A1 zBB08nti7N+Jl<*B?042OML1&J2{7q@lU=q-xyoOl$b};RjeaYU8Ib zB*|P)i>lu3;e?d?IDfyp5u0n$<#Pxcykj7`Ya93*6!YIDLxQcU6IhA1nt5%4KwyD7NYP))=H=-1+~>dSdF_=dhKiKc{4N4H_NL%-ppE5&C4l(t(eG&-Vaj+g5iB^Y#u`lU5)1 zAB2NU9bHOZmrI^%T(BKuC09FhucGePuimURCix~2^Z$9*jmQ&&u6h{-R4&9I*_(t; zXkR*|;d&}*SN1D4YApvEnw~|Hi;z%tB2+&Tnj7;sblpU$#$Q>oB?bNWs=gdHu5c2t zV+_Z~`1P&Z_JZorY(xGLB>XXgtktg0;#zVB$Eg4CZDudMQSHiX0BAmc(aho?Uu1k2L!iZ94r-SPjE-tM>MBZL4TVl+|K|eZ6)3=n2p%})u|^0+HVr~e z%}(E>A#t27Si}S!Gen&wgxh(+hD$WEwR|3D4X5>a1+n0JFP%A7#ZF-@ff! zZ@6@I{#cPkn#Mc#KHPVs%FO}&!V>_#7JTO`4P}G?sTcKQX|3(n3aDIrBut_-mc^Tx9wey>eVT>@JRB9Vu_ODYxi z<5R%buJ8hn)6)u&9R(*J8C1UQEzIj-WN1*N`Gt#>(@+Oc5>UBcfsqM)hyB~p7`@$x z8#3hOgxuAJzS(3{q9v#AU`?)<%urE7&*PW zyAO`gp$%9W&+Ldl*PbKtRu$@|e61gscj69gD%fCi2yrN%aV~%VPt{qh7qGyJ$~G84 zlrE7sm33rRWw*(`3zADl2XTl6jHS=rHXalU{ ztO9!?JifhQq2icpKN>ZCy=O($91W@4d5s)1HKp_#U-7zRu$U%7R+)Bl$={pw;puy> zJJL?(=K&3R-8wwK*>|X$-=&T&TjQG?cnHTT>%bOw!JATWhJ_AfcPI<~s~Y0;)UmRM zz#sWB-$&wYNE>ypV4nN0SOvN){h*FOd8vt(27>xVKn~4vUz7_g40$Sr{VLP})+Y6`v6CElN-O zaq~IEaL5)qwLOA6M-S18@PcZB%FMT=ISYW)0&y)W0lm4-)!!>fqT@gb@I z^*!ND``r}LUvlQ=v-&-a-;2v2cpk+nHy=F$!@|W)`T2c@U|lE=#5yUSM`o?uVKnh6 z2&|6$@;=7A1v{JWx;zr2eJfbhYI{?I7DmMsU}xy5OGWJ83=4oJf)4QOo2nCdt0pFAScm* zGz69XGHBv?Wpmg0Jq&fGx(%Y}zbD24uhtgj#50l|*D2pq z*u8*u1#@{Szny~EIQd@?QydAbKv`7f%kB@cc~*p9XnPbP2r3=EmlTg-TP@QYcA%Gv zEad%ZePQs(^n;Jbt>Kh4;+eSItQ;bG=^mGs1Hg+pdJ+5YaUs+lH(RqC}?x9a61r4hIE73_7BX)VQ%{_drxN8i2?c78W-BmDIfsP4f8W!hz zf4~kG3Ed5AK*TxJupiR^U$2~To>L|H)hFZoTW$3wL$16y7y6#D7-7RHrL5QQg2b|c z6!kVP9MmySbKlo+!NA33d4XO$HnvHfD#S;AGCjL-L{A;y3ydAjWgZBJK(G<&ZgcrHGV z2`WOm)uG$-{UXe?6x14y5e_*)k4Q8yOYkui2c4jc0Ezj1OK0)r*5m{WhB=!IyQyg% zBKGyG|ER(<|5(Au4t(24(2So9i{DF-?8~ z$jLnSbvEmC^(c}|S|b&uu zqwxXKq+2I9VQPPO1S4e9)Bati14ig@%CPG!OqW$G0DS1ZXY#=tDK>PP=! zA#iM%ab4K@;vaQ-qm|;jPX5brZ8#Vw|H|#}UYJ&9!DInB(D_j7Be(Z3qVg}~Y01QX zJI+5!uz}aYDKe+}-}%bUHh|i5PY2& za@Kqjto}2An)-E*`n%N}0qKR4LM~^hcBzqnUD6M5fC&TOYg{*{wt2gmufy4^9cs*O zQW~}liG7P-^IOcaP zdK!uS?|4C3xIdb4#6MR$D&(dIs;XaCpBd~Y`%s#WIQ8Y+MTYp`m{xLcCk)Ik^5nUn z41vWMb-O4T+2LF(agW#KTtOXmkfQpv>kGV{8~5Iq;?pqYE;_tQ?X@W$^JA!w;;vB{ z2bwK7zJ3}k@0Ue|n+lOVy# zvH(=E0sr8-6P>Dw$ydKvlhxLiwH;FN|p~EqLJqJ)diZ(r))L`H7Gdhog zP>4_*`po&(dd@y?2jtgGU?Uqd^k$jhI~5OMIiFuXSiH=Cbu5j=3BaV`t8=Qf9| z4$UNXvn4|2Ni78Obox@11e%wAgNidl!ru^7LjMdDvO1?x6%n6fC4qzY7C=0>_!2J_ zM4uikuW!wjX3&A4COWm|=MIXVDaoo}73ljH^D4vxjn3t1R1II@UjpDzvHp^OcD?rn{p?jG}+Q8<&Uxo zyToe|7#?(wmQz0h4So7}sKlXPBy8!2EI$2k;f$b>R&=oJ#i_}i_mt*LCXfKV0~&7D zll8gMp;8ZX)g<5DTY~w07*_5c6wn8XvMt&@=J(wRiDTf%5gD33oW7!HduC?tmA98t&$EfpvX91MNGeH|$Ahmg;1P*nAEu)C4 zDM!ev_{Qs~u3NWfo18k!FRxz}pW&A+X*iZvP|ODVs1ShAf{4o)?Aa>!fDc@dE`0>R z9;7XaC-uQy5bfUA65T1&$fVENUPKf9#)1RN5Gs&?7b13v`JT)uh3m!$Zux8Soe{Ao zvu|}55B$gzJ$&3c4*v3e_)ylC`GM^-;2dvj;8E;(=>CY>WT|~e)l^Gyt1szYtG8l5 zVa3!wH2_*CUYWm7{lEH2bN9l*I>)vblNGyf=s>3_C_H>-N z2H*zxcU$UnNrmVDpryQ0wVxKqnVZCGHeR7n$vO~=a#d8U3l!#>+z&r=y=crFM%0k%H>~wuy2iY zP5?)1#$N|;V*h_FeRV)o-}ClexO<>^c#WVxjKx+E-C;U-89bB7X?) z#^bVH^^u88Q*P4>n2D37pbS+)E&aEKrrjE^p@{^k3I`@Rz*;oRQA3<%MNCpg9}53H zy5CfVz1dQsuH0G~dS9iz7$<)33qLNTKGojcMSqw9?|6c*G`}J^j-#R!+Td?x3s8pH z`C+B25Q2&Yr&uXu@b*3_b#+KX%ZBfbJh1fDo)1bz@3e~Wb*~N63C>v7N0SE6G!!bl z?ffGK*(w<|U0W+mYf<=~(x?Wgs)2fyS2XFPq4(Q3y=al2;E8?00x?Td?0SM|zc@2o zoPCxrx(}rjy#mUBe!`SKqS!p9A8=ptT`iLH= z=m=JpH-n6yA8Uy~W`4(5gZO^mjnV(*6)*)0>ko!*-8d4t`;c_3Z(?7Dm4pb)^f`_< zS6>)8tJAcnWU5B>|!`KV!PhI_*|{Ad3ZR{V8aw`mj&#wKxvjd%xSS z`#?7ChwVSL;k!3buQ8rebDXu7Xu0i%^&NO5c}l;Brcet8$7{Xm`Smlm3DQ9Mm;7GU-#q^r-8RWNyb~Reu7JJaF3K*b zYV`Am{jec){SG9iDIZ*gbq4z*u9f@0rx(oOVGcRo?R}C{_rP|bbBH+~xUTkF*?p9{ zGK&ctyX;BSZn^C%L`?KD5oxSAGHFQhe%-ZFF8>X?qL~}|59xPQeQVz50+iNcD_We} z$qnvXu0<bfgTa)aZ^{i5G{^i*L3BjnHsR!$e0Eok5`Y=3MTG0=6@8oYI~Yr6hJBaf z@0&D<^7l%rJDlkyDQlFSaK?r(Ts6&AjETm9Aj~Fhz zp-<~o-d!)rpj=w4pTgJVZM+bPD=c2M7|st_=zHzhZ*LmiA0hW9GyCLChEza*mXo+U zANE7aD->)HON#A(om!2~%%3fJqn9*%SO zw)D34a4lb1W_NsqB`Zxjz>1gQx7aW&plck2vxpV+2QG9;hnY31++ZQ?Dd76lS8Eu?0s<~S{s5;|6E%EF zE`^lFX4wO^WeB@qOWErFEYa-baM!6MK^F`9i?4geL_o{9i*7L!hnJI zE)fX4@Q^0jp8NA<>lskO#ik$gDEH{n_)7jg9u(BhnKGDhkuRNqFE!?i4t`_#zAp2M zE)xGs!%7U+lP%P%_WYIiP7!PAYRaO^nMu~34T`x=I+rdR9vFXt5AJ5UE7$p7b^d-A zn4D&=*!kAWkd&g@wc~rJrS>9%{vM8=0^4XTQ?yONKxP2FXc%q$#C3)PgPZuZiA{gq zq8W~INt3J?7UzZ&)XNVYPBCr#Gg@&aj3~vr>-vnts|#zb%yz9{Vj(R16&A+KS2~oy z@xGoZ^TA5J@oQ9A%G+|-M?=(v;L852Ax4%GBSH4>MGm%2&s0Z{8tuZmX>Kdr^};hn zSrOHQo4gxQ9?f|fM8sC((6z(jEj ztD<=)BFo=dLrj-Im00LpUWokM%Yub31^t&xMTJ~A=rxs%$v{HXdE3c*$O2AdKM-P% zuiLBn=(9;cD}osLj`H#ewi2yYKEd#DGYyp0;Y?)5lpRZOXcf zt?i$MK+iP}yz9;Ke(~FO|BAU(omP0d7NSydch@zUU9XhZ0l}0_iq&p5_XN(F&Ac3J zfi!J_Zs(`zz@r&2|0aOhB+teE<$X2(#_~b1^J8m0Of2{m#GjmBxtBx-)mlg6B70qH>A1`3hw5RID7rZY@#_kaHF(rv zhjBfTkasAo|BhQZJ?^3-RxVbL@d8Mvty4 z$>lWV^q0uqw(|IFMmC&m;F{i>@(>P zRcVX8jQ^C#IoT{Iz5v1a`>IvRRnAozl$0T4`sVSM*ugEerq>X8S{*`2)e3*^ zJwm%7s)iB2pCaU-kN=zWk=0q4-G@2+^SPL2a~mdn8!Dv3r8F(>st;#q^N-z&2WEoI z?~0yO$}enw?oOh=xFfyirxJYSJ!N|Bw`l0o^Y*Hv#BLzBPd-1rOn-iqQOWg<|KO@S zgU8$Rj;}qRlQm1j?99iY&vUWis__eynEO;13TS5Xw4f0Z5C8tg-AyFB`i`xYG?Qtq zEu)g`{m}XUXq!)Tqh@;#^s>H9?KrP*`>71>n{9_*&X95c}aqY25Wx%E44>|GqnhgvhNNsK#*S0``c#=Bzo`~-wt!L1IwIz4T zQ6IBx*|XfPhUlZ-O9^L%j@8H&zfwdSYe(g;Uq7+4qMmxXBY3`(bf=j z5Et9{IPlHC3w=#=>z^XXoc`X8_y&{gfG$m{{?3%F@H$$ zW!UHvzG_^^N$2#LX_lgTDiqv=lCe=@)tz>*_8`8nv77lMP(Cd8r7oWLe(mAYw(N8*l{&1tuE5 zh9fr~2Qk7{ZQ-IpIf+P23E4Ha1;m9O8aQcr(+bsztdZU_&h*(#4$}&halgOxm%j*V zm>zmoM@KAgdGUU>;1Cyy1oT>85h}}}(AN{O_o&nGGP(^Ep$}Ht8z-#qe;f1iJ8nHP zzWwlHOdJ?kq<`X7QujbrQ7C0ZK#j4H5S!yxrQKQ7p$Eml=9{Qc*8k#}&eNC0Gs^Z$ z#2JkMvylOh`=?CnkG(1yk56dHVZ>m!OMV%S8FY=;3<^DbcNOUI``#@zG(|*~$Hp@t zY?|m;xZcqd2-|Q*06QQdZ`}RsbBWAuy{h2JQTr?Z|Hc|rR`cFp<;vOZKY46jbn^rJ zF>+3J@}k#D0x&&hi5GixwMR|Q`}<%^q4q!P{xnoCy(+!b3KBnU1Zk1K{7TgqcWKS5f_=u4c5|Vt;y}`MXM)=%!0&WVNchRa1S5pl_Q*p@F7P`^ig13!L(yN3*>~vE0n*2t5y~@h4^L?F{afhVh+UI|_Gs>*71BLkNGT{{@pV*g^xc=%9 zbE(33ro{iA<|p=zhdMT!6ka;I1wv#WQYF2I^YHMV16Ga1C{&i~cF>LB)(%ZPOwz;I z??-!A%=eVz>3(EkT>L&b^^6(+WE)iZd&L8;DejcJbT#;2rM8<|QEQp|_8Q2iP zcha6w$V@s~vqp!ldStZvSm$PGpEy5h&LxHg0}dC417bDpBGZGs?#?ZSE7};qo5r({ z`L8qmf4{8h>iM;wu1-r@?eQ(!qZ<2rq$z!#X^uh5FUzc@qcpS0dj3z8pDdT-UGqW8 zx!x5K{X#Q>V19Q>D*JR5r ztlBaToGVZjnL==3{maLPQF>Ja@C_yhwH5z@;AI7+jWIbv9b}(Aa)3{IyRptH-2Mbi z^VVuLV@UqZn5J~5l8)>sPOX*I$iK31%7&7ijrPs)6B)c~1(3T(Nq3(9xi;+I>eP+s z*23t2yl+{`GAEf9@|_R&O-H^@AMZINQ1(#e9?Y= zfi_|Lu)12>&pDPhGlrjZ>70~?qx~8u?;n;Ri9#URCH(YkuNF!E3pC9Gqv;bV0$g(BI4iHbI{@?$>OyMVBvaK?o{m zG76b5Gkl6o$OTCj=4(0@|HDP@jt>bNtqA|k=_HQc042j)n=NnuqJ%(B@@Ss*h3$I!8GCRhR+(8Xm3c7{;8c!P%5Z`bvpm}(d%ktB8vUL)+q|P1k?)GagJi9 zE^ZAxd}X0_N+GGwv%;I`UL5`c>l$2RgrgggjzG1lZWRQ<+L{vjaxBy^9x~-;*WcSN zj+{WLG=fXg&_@tQR(^(bUN^mkG>AEo%(DV0%d%LXZ-}^DHf?%qp*5KyVKVy&bBGKO zYVg}H>XKh$6Y@ZJOj8^25u1E=OQ8;Y`m<%pNF5HIU#QhP#n%67Lgw?huAOa|Kx!i{ zie!dCW#E>fYyR_z6M4~pU>=M1^TU@@fsOGfXO4gAaXoJ%<+N(aPO*e$-X+B4Ooo5R zB5(R$GrW&_q#AwXkU?#zST@r!=jJ+GMb#}0=a#L%@4jwwgCo&5e)^P6xPH3@P4Ymy z==Nc8TP##uC=2Q9v}EQ#d9z0Z`z^?*T=^11u4ZNNg!e{fskQ0bB7XxWv{e{+e-fGJ zcqe1!GpGS%9)`5Oek3E#?lxv=w~{d~n>nz;eSDWVZ^aW?mYY;?az|ECAM9$(uVbil zglNy1mbCT)YmEX@g#Hc?BnbTTz1_a2A}^4Gt5{IC=?ERZ3C{Dn>p`RaE_~o&c%Mr4 zDgK|CLr@6#C04Ky-q8cfYbhLFeN-}j(MjI7%IMKZ_!(Tj6?}`lh>0w|Qs8Um)q4XA zy;j+kr!QftS5V`zttuZ!0{!e+Q#rtF&4jzXUx7*oa_qjitiwDIBYbK?l28JeGeOFXJl)2mvQWP?eiwo#fvP9 z<${O1-&jCJDBvNBwW74Tll?f$2JMjW$E4A5gd8$-Na_>DzG0QRGb&1U?1|T63oGEH z5qf%g#z`TQ&(fuc!2LGkz$R7bQGmodxX^l?)OeCrF7q#XrdBs4l)bc?wIX^}C^Od<|Be!lXu?fau+bTu_U{AVSb z&8+SD&Yvod`Jv&%lSx%>C->>!=~}?%?L*<1a0fZ-+W1|}!5thk`89U>S11pk)vBi9 z2V6;gcYEVsSxuboq+z=!JOL((>K3;CyfW&;2S`zQ)Nxm}~bIp`jPZ#Qz zwLcT`9k|ksmr!$`+o^Vtll>~8KLLMCB&VUt*!wqXO-@A(%K(Wf&+wm`JNc|ZjdNCo zAk&};7?6o4&vFg0hzSoE*8N%H_tvg*wMQrY4hCdM$7we!8uV|fKZQ}0W}fI_WokGv zbfaZM(`Gw18ev_BM*cIF*Zho&E;qh2c7?ihRBmfV(^$pYxq=`~tkm-Mvyr&icj5Cj zxMF!pSy~NS>Ft5&P8+ok!5zQxboAOq`jhu#?(W z5eX=+OlWU$=t%rIFR})Ls6sBTJd=+E9A&d-BOd&Oud%znlt%%^GsN3vl@HIc<9Rcb zl~V5^t-^!NMiy|t=bO?97HT`>^`TUID+e;Hx(vjgcF1U0yM0K+VxbzZzk><->Y`Ok znSej?Oo*#K3PE*jA4K*C_gJe#a#9LAKa?1!17Y(udE>Y8x6R-*-O>?=n*2Edbl;-ZO$8$$h1BP4@{fJuqnOuRMjwUHkyIT;QNi<~})1+$EutB&+ z*ZZcd5$Ee!k0%i;qJKT&-&G|4;`U0{kLMaAtx=+lYA*8 z{<_x-%0d^)Et%k~PckQ)qDbagXG2NS$r+0_YJQnJQyX8QFn`hBxkEYFp>YpNtAjo> zhaCQQD_ZmR~E~T^)SH8-6;qJ#Dmn^H?28B9Y1C)7VHu@baTB2ky za*2}qeV;YB8ZW=V;jLETmC5{<{oP7)ig$k$=YI0q6t3Dzn=$_4=XOG>D5$=oPU#Ud z`RM(Rrr*hA9j7gSM4-6zbR)8*e%wRG!f5QN<>>G3QhN>8{YU5Duy%KcqzpJZrl=ds z_iZb~&|yKJx!y_rmD?OemBLU}AMW6+w z;v@-r%TN?;zpJ+sftmy8aziH@P}SvPB|NY)QTWgC5c|=dg2e~VIW${DT#fqL$nk6; zTPr96uAzr{yaV}1UyZ6h?BPn8P-#K;^Xe>@>>OHepThEU!45U@P zS#@+CK!jO1es{j@e$mT@q-K)^1_VjeWSi6-BlvfJt#YnPezDc<*zkirh~3NH3@6M_~~Oimi2|?k~FfMpY=Ga-N{e00trhiDxQFRM z7d=7N5|XW$ULo^|?6&M09i;#IW18(p?u=H)Dsi{%M;wFS$0G|R7Hf&6iL#|z=cq?k zRP=o_5x42J{a#yHEY>KS0nY}@z$?+bFd&Au5vzkmu*f=J?@)`~zGvor+(ji@;X;Cp zxU3##JJ-7gZ{PjzcU=ekSL1#=S08^^LL0SEp<$<4HWT)PfL9-UoiK6gV{U5yO2TSg ze&2`gX{@NTW8EElAN4bw)xn%>I<=dN?3Kc0Eh46Myj>8A1Vdu-E@cAc1V(FI2sbJ} zrV6>dbHGbs0^+_J#>zE7OkXCB6k-S?;5;lGh?A6Sy3Y{v812oT*x#+1^@$a6e5~7b z^fQjt<|>zx_V9fl4Ei!xG()sl0ms#3$D89hoKj$U0^KkEwD;kGQwBv|VpJz~H!pO^ zMB)z@l1OJKk);h-=$q4AanY^XwI)^yN5rWJIouU25(HEYn9ZnLF2 z5`1ZeHI_IzI3{cL;}^ehKGdVyE?a@{xE^myAGpxTFvD3t!@<@ zQ^X6JO6%kc?P#>w!$sSIa(6pS;vgYF45)UhO#_x-kgZ5Two9&6fm(M)eA=t62^Z!z zk%qf4hsb!{97jj*sRBcO{6UvQM*a1_yVlUixqq5f1f-XW_!MW`(_9{Xtl8m0_G_~q zG8>Yb{O#OZ-e`xy>V{F3K!r#?JH(g`kFxqh6+09%a{RK4#s6?f`5CJgM9S&u2U`l%<1 zr8Io@>jq8^v7s@I7IN{#cXFi5t5=D0Jyl>A&j@g};pTpX0nNV;7gWgbT? zbmA6s|L8brAkI~WcRd2r_Al;?#gX*NG(>Y_amkS9ZNJIR?7#|DBP9%@5zkCVE8lm% zaS%CslKO6uhsXcjdizuA;cAK;6so5vZLogpU6w(^jsn^q!blcJx3qwSNdr{CLP76_ zpVo?G;$I@0=jXRt_>kkfs;AJhI2Y)7=VOJ3dGT2mIfO4G7*{mm+{(V*1 zW9$atNO#+0@}>Pd&A#HuF2#1BArYB%S#LaC7?GH+E8pXNch{y05%-Ovd7Cg>%_QuA z93Cz3lS$~mIvqld2a1n$Tf=LCQ!Yx=k4KT(m!K)WFV-ge5ZynYp(^=$$V;=LVrsI6m!e=j?_3IA*bezOHp%g4jp z2OYZh^OId{G;m(vIH^AWT7>@{5D5@n2K2tJst^ExW}?SsB)b(SY0$=%Pj)|{j6M%-A29;O#A&*$c7LwTV!u{+O|Fk#yKAN=Bg z(%~vCnj-%U06#keEV{!j2YfsFq&+nQbuxblRoq5#J1!BPk~DSV3H=9j%oir&!6xEAWMLV<^h=YNWk z1m9j|SxV|kTX=VCmHw-*x824Uw_}`ptcECPl`!wz!{MfqFojL7FAZnH(r4wMp+wih>j-%ElPJX2Lg~y zIs)cn^B-?P5P_-A2^+HV<`cf3wfEQ0-D6}G_-p=gV=M0Yl~w2O^{5*qm~I#etBnw1 z@uL7be1NThDs18epRs@F!o=@>R_ZKf(+lTgw;oX>-akJBk)V~H+-)K%Y|c{d9hHrrxJ40 z;)jo${|()RY!0eoud(M{*Wio~BOmJ4tyl9uF$Do}>?%BKgVM)!n<4HpUt`+>&R zrFek-8U13yDCg;Wd6dOXuy>-p2a5u*%)l6aU?177QEV;Mfixv0W9lNplP`d`Q2J{E z-`{aN-=H!dLgb^Hh^+970LQM+w}zx3o1Q<_;*`VST5OA|tgDo-w8-0XVX+&$UyKrC z#M}cbwl36?kz?#Qm1}?B`E1~qWtz}UY?Y9_>=MGn(XA0WzFNUPQNIbnzSu}}_bHVv z?yJPb+(0$)VG?lQd>18|=Kk^H3o*4hA_tpB%wpNP(?h z9W9yCd$HN?`3(MO*GKhFn;0)l8<52r1yKx#iJR!1lpx}kwYklO2oxEiCcs>8Amg6o z(^5$4-S+OABhrdl^1>Lh&n>T*&vx(W(*3!aFILJ3ljNf+E5-SKQ)%hm(Jx)Oe?4RX z*pJ`ranpR{WyF$1=poBIrQi+dxDU%Uwfp!(*^r{ngcSv6Yx5kJCSy)l)x!8?pP_0G z1Nr!y&4tHy&s(a(YaP!b-AWJX$ zW;b9LI$+BDC+zSlc+hgd;Pd`|7%PcAEQq4!Ph=*w^lY@G9J3S_$I*_hRg(ivWGVbKFebJ zQ%E&7`Y>&k7D!P8O=sC~p}KAnkefTErp37XnqcD@o5k@=vH$CoYIXfpO=`absN0i= zcld{+@bK01A*5lo`w2Ew%T`W*Zr}cKwSD-?BGDIE>Bx_=?;{vR9dbqB;h{b+j88X) zq!!D#eFY&9_ga#)w6ogq1yX-Yh(R$)ahODTSa<5|T^LbChLNi|l%40+q*KO>Ey>0B z(6OOkuIh%5+@D8_=86CVtah@!PNuZo70AkkFa=wc+b>^)bu&0wi3Co)zE0osHDm#I zDo{e9MkUT_AjA>9cJ^9~x*lzRKfgk9mF@e+b0I_Shdl^u*EI{Z=}Y+0!L&#NszzC?o=L@m?n@At$G*=l-(HN^z6jUm0%)m} zFX-Kyd)O$@O=ImHvN5%HOk)M*Jc)Xk52dkYDA$tgIu1v#WU=3%(V4Q{Zz=`4Lw}hW z8owMhv&&6A61kD&o%OfZoHv%gKpWGH{ftLGL3dD=Q^rZ~A>QR?QDm8&3OTfi`ubNr z=>u{5m5O{)_*Rh|q<~y#ZB~l0`5HEp{Iv8R}VJ8tK{_U&|HyJ7% z8s6@z`tS)+_SWkzmLNAj*|H`$%Zkt42*W8o74@(mA4C|g&rPQwooiJ=L86&3zXR79 z8^o-x_Q=)Qz2<347FxM2Y50YW0PGwLwl&$sXAt+8SFQ^zKsFFEcvTId$Z|uOx(PTb^ zIC(A4nknV9(XPNLl=#fS0qh`t(Y?}pi(l23O>U<=aCuY^xJb4}wd?Qxj1YOldG3C~ zMPmujoKS19n6$4RCgV$$yY}U73t2)LF7)DLSuuC?FisP))#{w`uSUf9=cVw;M!?kg zrVZ92LvI$8IM)!ubTTr`-Q7{%3ZhjIej4Pix=r$X6&z@#(Iw);8k*i0Y@c^t3UBBU1aOtl|0Oh8hw`xW({tg0`3_;#Dz?)Cm#TXrh@r<4OQ|Pf&1L&hQ<}xD1NPsIhj!*eu0l+;fHp{~zP2YPkf=OUYF8yMW@fauX4ZYc zr#1{GklOD;^k}m~Wt@faVXbB)f1LraCBsny|FCR8_&a482rC9tzZ29I?Eu5~VBt`lh>H3DP3Y1^q_0c1ZQRPLCf|M3wX zRM3~4h#Nsr1E^5C>8K4~3tmX9QDAa{u%OVrXVwn0q*I^7fO64MDuZhfBfqHpF&ar| z#)Zg050SoyZDTgZXzwO9f@2UmUF1u-MKF&>qo47wu|O32X;LR+&L{FyEvNZEk4-Wh zIPVQ%Wz)wNbziqfM#EIV6x0H1J$(XVfqu)Q7L+88AqJ<6q*YRCCBrX_=jKor&3#WI zh=#!(TFBeoW=`r5H)F8G-S`jTt~?^a>8P{U1@8OQkklUZb!ezERmY4cL)noNkDrJ6 z_U6rPCaX@ZR@#fJ|2fEgi$)eu1&fhf&Ra~J+^jL0Nmzl-+;CxhhIL~5XAnISFnbxb zuP+=2ENetTNKxOPlLZ-Jzbhb@hxW$5W^8bPIaE8T7^EfBj6&txooofPA&S8MP0-2O zKi&O&b8A;JjFn9a3TsTQnQ(8}c~qmXn>+-r84F{ageS-$z=$dRi3W0~ zDiml+X!ZjyD$#w5dhKSx&B&GsLe9E4yEniiWNpeYN|5V4S&l^>uA)q2QTNL2h4)~R z-4i(HUN{kPmK0CJ|KZMq`^FK#407Do+*}I&8w|dZ*z@najwxhzH$w$I!WKJ9c`d-m zn%TWTENHhA0M5L$rowLzk+Ukf{9&n&WVYRzC;wrST-73Ory#8TS^o@NiaEMBI`W}4 zqa%Jo+We^3V809LZ~eAu`@-=259J9QWd2G=)|9O;@}hQ;;I$_t)0-oJK^<$SXQal+o&>itC^ z4HG1QGVqNi%i{XL$G5cLP#8+NU3EdAx0-%oES_hnn3i`nRKXNKxk>Etqh z?#`fFGSs4p0o*cVgIFwtWTmD4M6a(I=kdVJbx7J)(QXf}?HYX7K>}WriUjwtnm$yN zOms5hs{rU!KgOQf8(0-Rf_<)f|kq3?NmZA>FT6^*v}n zh(QBsjGBopgh^@IV*rWt!%7~zBp-0ZQvJv4C>4P(i69WGq05rqO8^==+|pkBu4j_rKDVf4y75LxH~v~yYzeW$5X0*`Vpz8Hl>+Fw^A$8>p(quwZf~Q7PL!mzUfYY*5H)A>GqPu<2?kT%-0&r966Gyj z70dUlcXS#_AFy^RxNg}ju5QEb03T6Vj;W9*iwB$uZVqBRSONAtXmVln@)hdj2X$q2 zaXeXK7Xn97-`~ePq%+I=&aKM_(pt+vU?R%D4RK6kgN8U~6J6SKqkYzyG|&)JV?mCv zTWDL)vAS9pds{_k*UF_Hy|9NY9WA&4=V`XuZHcik_Zyx=M{s3ey-3F7t}}}a6aA5y zO^W``abR9;m(O%6im82Xr8|j;?Mc`l-e*7-#cTgU^Y3owM zNcoTSn?M%m3zZ3?Kq+)np_I~M`O_ugsIaQfN2yQOSPDVM#rYSp&v>i|9~Lh_h^u06 zdD0-IeYA2#+xXE80Clxf&!}3}w=QNt>Fg8sXG4@JHdh=-B!Xtl_JZBW@(KkIzzrfs zVVZ7gu<$1!g%|N#Qer;MC>cDDa@%?1k!XSne5r zLc2ci#%6y!kw&dcGQwVz0U1|_Vl^QoI8z>Ph;WdNliya*JhB75OP;*Cb`bleS+Vb@ zzz9>PoS@cA7THyX0yUgHNm^oaMwhBJI#ABtJEv^T2YxPhOQ&tgQ7cb7vg8jU?&;h& z(JK(9V$6{s4t0FiN$ItNtEFvYL3BxPB!IyTyCq!x$#MeqU!F zdCaPX_b#jez)#`WzjwWM zXg0L^h^kvEP(_ige@MYLOPQ9yE;q|!B`%GnQJMl7VcOm~>(SOkO9(04$Y0RVRipqG z(_15*!W5wEMm%uwv1$N4y+N-F&Wnh-Ip{$$gDkV@FH$J@O8P63(cNZgGi>y$~P{8f*2iF8* z^c_}5h8A^yus+;4%ZF%eoSuz4|Kycqu6xjI5PhHZBOlpLKF)cyA#>^QW+%6TGrNvV zH7lv$W)i!L8_eY|j_i12FHu}T917YK-gL!U&%Z7b4h27rJEjc3((KqFXg#rz|3`(`tNmU2je6E=89H6 zVsrbcE3Kjx3~x*Uz2xjp-0^xXYj>9wH19p?`}_)B=9sm{b{#)RuZ_-Zh~YgU{ApUQ>4zNUJ@?oj>pp zS=dWfnhCnj@p^X`(YEu|k;Irobwny}Cd8eHDyE!ZKT2=92G-s|?dsQXS2^@9&p!u! z3qybj@G*P8w{E3FW4XIDqWI3JQVSCiYrJHdTiAH?QI>VQWBiYkr1wmuSJMoRtc$1H z1e;HDKf0Cc7;L1E)!O8frn#SyY2R>#Sh`9=7AgbOTR#$YT(yg$9Tu)(Cm=dyGYt2%OZ?oQk>p>wtpx{P*dU&-7u3cb3~5DaLez@S^O@S0 zi}eqG39_@B-PY#MR0w|qn&0V{(!h3trk3kX8$*82-Mp9wCLO!hw4F%(l+SsQ9_Q20 zzhla$N=3haC&u&L)zoXcCo}M3-V%CsIurmNCSN!8QTQ66$PqU0Q;)AHWM4$y zgG62_wHP7?V!H@X>ss^r6 zT>!yJu=MdUU=Xwl8*&BnMA_=R$>f5qMol{2;7vAI_$Yq`SF z=G(32cmzB8HfZ6P{4|Q2Z8D7Z z3ZOZmt*E|M%*uxy+4N#s6ZbT4Md@UNuel&~*xjgRst%430=cDMTzKjF6PwEyUL3p< zOOL2WQ*v`?fYo^#v3IxGNX z+0s56ZNo%5Zv=(pihlhzfn_5{cdbR!7|22s@+D7zE`bc4oU}%OG+-105$$l_5z*I} zFNAczFd9&u)=D=dp0;7@B9}HR)Z_78;^_7BUcUK{`56+{FhabU?J zD-rFaiJPF0g?zD2km1LqCn4#(;o$+y*~jTEI**IiBhGV`c~SsQ*6(fxUR>=2(;W0x zH7F@(wr7<*FO%gTnZ5+Feqo?5^0{OMUJftBjO1g_^LN3az#6uqkPsTMQ6wdq#m^H| z1nSljCs-8(k*I%;4$4@Hq1ZosuTfFE*(61RiWCl>xir5vLEULs!p|0v=kwEEg wR?{u0@Y%O(Rt{Lo|8;`@Upsh>gKO9$moLShG-XAgP72a^sH;+{Wb^X>0UF3n0ssI2 diff --git a/build/icons/imagesharp-logo-64.png b/build/icons/imagesharp-logo-64.png deleted file mode 100644 index 2d9a0045e42c42c517d4351157eaa5198cebd7fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3736 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 diff --git a/build/icons/imagesharp-logo.svg b/build/icons/imagesharp-logo.svg deleted file mode 100644 index 620287457a..0000000000 --- a/build/icons/imagesharp-logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/run-tests.ps1 b/run-tests.ps1 index 2d563c67e6..c356495440 100644 --- a/run-tests.ps1 +++ b/run-tests.ps1 @@ -1,86 +1,71 @@ param( - [string]$targetFramework, - [string]$is32Bit = "False", - [string]$skipCodeCov = $false + [string]$os, + [string]$targetFramework, + [string]$doCoverage = "False", + [string]$is32Bit = "False" ) -if (!$targetFramework){ - Write-Host "run-tests.ps1 ERROR: targetFramework is undefined!" - exit 1 +if (!$os) { + Write-Host "run-tests.ps1 ERROR: os is undefined!" + exit 1 +} + +if (!$targetFramework) { + Write-Host "run-tests.ps1 ERROR: targetFramework is undefined!" + exit 1 } function VerifyPath($path, $errorMessage) { - if (!(Test-Path -Path $path)) { - Write-Host "run-tests.ps1 $errorMessage `n $xunitRunnerPath" - exit 1 - } + if (!(Test-Path -Path $path)) { + Write-Host "run-tests.ps1 $errorMessage `n $xunitRunnerPath" + exit 1 + } } function CheckSubmoduleStatus() { - $submoduleStatus = (git submodule status) | Out-String - # if the result string is empty, the command failed to run (we didn't capture the error stream) - if ($submoduleStatus) { - # git has been called successfully, what about the status? - if (($submoduleStatus -match "\-") -or ($submoduleStatus -match "\(\(null\)\)")) - { - # submodule has not been initialized! - return 2; - } - elseif ($submoduleStatus -match "\+") - { - # submodule is not synced: - return 1; - } - else { - # everything fine: - return 0; - } - } else { - # git call failed, so we should warn - return 3; + $submoduleStatus = (git submodule status) | Out-String + # if the result string is empty, the command failed to run (we didn't capture the error stream) + if ($submoduleStatus) { + # git has been called successfully, what about the status? + if (($submoduleStatus -match "\-") -or ($submoduleStatus -match "\(\(null\)\)")) { + # submodule has not been initialized! + return 2; } -} - - -if ( ($targetFramework -eq "netcoreapp2.1") -and ($env:CI -eq "True") -and ($is32Bit -ne "True") -and $skipCodeCov -ne $true) { - # We execute CodeCoverage.cmd only for one specific job on CI (netcoreapp2.1 + 64bit ) - $testRunnerCmd = "./tests/CodeCoverage/CodeCoverage.ps1" -} -elseif ($targetFramework -eq "mono") { - $testDllPath = "$PSScriptRoot\tests\ImageSharp.Tests\bin\Release\net462\SixLabors.ImageSharp.Tests.dll" - VerifyPath($testDllPath, "test dll missing:") - - $xunitRunnerPath = "${env:HOMEPATH}\.nuget\packages\xunit.runner.console\2.3.1\tools\net452\" - - VerifyPath($xunitRunnerPath, "xunit console runner is missing on path:") - - cd "$xunitRunnerPath" - - if ($is32Bit -ne "True") { - $monoPath = "${env:PROGRAMFILES}\Mono\bin\mono.exe" + elseif ($submoduleStatus -match "\+") { + # submodule is not synced: + return 1; } else { - $monoPath = "${env:ProgramFiles(x86)}\Mono\bin\mono.exe" + # everything fine: + return 0; } + } + else { + # git call failed, so we should warn + return 3; + } +} - VerifyPath($monoPath, "mono runtime missing:") - - $testRunnerCmd = "& `"${monoPath}`" .\xunit.console.exe `"${testDllPath}`"" +if (($os -eq "windows-latest") -and ($doCoverage -eq "True") -and ($env:CI -eq "True") -and ($is32Bit -ne "True")) { + # We execute CodeCoverage.cmd only for one specific job on CI (windows + coverageTargetFramework + 64bit ) + $testRunnerCmd = ".\tests\CodeCoverage\CodeCoverage.cmd" } else { - cd .\tests\ImageSharp.Tests - $xunitArgs = "-nobuild -c Release -framework $targetFramework" + Set-Location .\tests + $xunitArgs = "-nobuild -c Release -framework $targetFramework" - if ($targetFramework -eq "netcoreapp2.1") { - # There were issues matching the correct installed runtime if we do not specify it explicitly: - $xunitArgs += " --fx-version 2.1.0" - } + $coreTargetFrameworkRegex = '^netcoreapp(\d+\.\d+)$' + if ($targetFramework -match $coreTargetFrameworkRegex) { + # There were issues matching the correct installed runtime if we do not specify it explicitly: + $fxVersion = $matches[1] + ".0" + $xunitArgs += " --fx-version $fxVersion" + } - if ($is32Bit -eq "True") { - $xunitArgs += " -x86" - } + if ($is32Bit -eq "True") { + $xunitArgs += " -x86" + } - $testRunnerCmd = "dotnet xunit $xunitArgs" + $testRunnerCmd = "dotnet xunit $xunitArgs" } Write-Host "running:" @@ -89,25 +74,28 @@ Write-Host "..." Invoke-Expression $testRunnerCmd -cd $PSScriptRoot +Set-Location $PSScriptRoot $exitCodeOfTests = $LASTEXITCODE; if (0 -ne ([int]$exitCodeOfTests)) { - # check submodule status - $submoduleStatus = CheckSubmoduleStatus - if ([int]$submoduleStatus -eq 1) { - # not synced - Write-Host -ForegroundColor Yellow "Check if submodules are up to date. You can use 'git submodule update' to fix this"; - } elseif ($submoduleStatus -eq 2) { - # not initialized - Write-Host -ForegroundColor Yellow "Check if submodules are initialized. You can run 'git submodule init' to initialize them." - } elseif ($submoduleStatus -eq 3) { - # git not found, maybe submodules not synced? - Write-Host -ForegroundColor Yellow "Could not check if submodules are initialized correctly. Maybe git is not installed?" - } else { - #Write-Host "Submodules are up to date"; - } + # check submodule status + $submoduleStatus = CheckSubmoduleStatus + if ([int]$submoduleStatus -eq 1) { + # not synced + Write-Host -ForegroundColor Yellow "Check if submodules are up to date. You can use 'git submodule update' to fix this"; + } + elseif ($submoduleStatus -eq 2) { + # not initialized + Write-Host -ForegroundColor Yellow "Check if submodules are initialized. You can run 'git submodule init' to initialize them." + } + elseif ($submoduleStatus -eq 3) { + # git not found, maybe submodules not synced? + Write-Host -ForegroundColor Yellow "Could not check if submodules are initialized correctly. Maybe git is not installed?" + } + else { + #Write-Host "Submodules are up to date"; + } } exit $exitCodeOfTests diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 28343eaaa5..8ca1f2ba5e 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -118,10 +118,6 @@ - - - - TextTemplatingFileGenerator diff --git a/tests/CodeCoverage/CodeCoverage.cmd b/tests/CodeCoverage/CodeCoverage.cmd index 01e342b3d2..9b14c163c7 100644 --- a/tests/CodeCoverage/CodeCoverage.cmd +++ b/tests/CodeCoverage/CodeCoverage.cmd @@ -12,10 +12,10 @@ dotnet restore ImageSharp.sln rem Clean the solution to force a rebuild with /p:codecov=true dotnet clean ImageSharp.sln -c Release rem The -threshold options prevents this taking ages... -tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f netcoreapp2.1 /p:codecov=true" -register:user -threshold:10 -oldStyle -safemode:off -output:.\ImageSharp.Coverage.xml -hideskipped:All -returntargetcode -filter:"+[SixLabors.ImageSharp*]*" +tests\CodeCoverage\OpenCover.4.7.922\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f netcoreapp2.1 /p:codecov=true" -register:user -threshold:10 -oldStyle -safemode:off -output:.\ImageSharp.Coverage.xml -hideskipped:All -returntargetcode -filter:"+[SixLabors.ImageSharp*]*" if %errorlevel% neq 0 exit /b %errorlevel% SET PATH=C:\\Python34;C:\\Python34\\Scripts;%PATH% pip install codecov -codecov -f "ImageSharp.Coverage.xml" \ No newline at end of file +codecov -f "ImageSharp.Coverage.xml" diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 97bd9b6e7c..9c6fdae3d3 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -13,6 +13,7 @@ $(MSBuildAllProjects);$(MSBuildThisFileDirectory)..\Directory.Build.props tests + false @@ -25,6 +26,11 @@ + + + + + diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 92c3d79edd..a25b548f2b 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -7,7 +7,6 @@ SixLabors.ImageSharp.Benchmarks netcoreapp2.1 $(TargetFrameworks);net472 - false false @@ -25,8 +24,4 @@ - - - - diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index d340b2c845..f7959df6af 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -22,9 +22,5 @@ - - - - - + diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index d71f0958bc..1c909faab6 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -21,10 +21,6 @@ - - - - PreserveNewest @@ -37,9 +33,5 @@ - - - - From 9fdc4eae8d6e1be5f5d75e3bff39c81c820a92a4 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 12:34:20 +1100 Subject: [PATCH 04/53] Update build-and-test.yml --- .github/workflows/build-and-test.yml | 46 ++++++++++++---------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 825c1f1cad..3869517f96 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -69,30 +69,24 @@ jobs: token: ${{secrets.CODECOV_TOKEN}} file: "coverage.xml" flags: unittests - # Publish: - runs-on: windows-latest - needs: [Build] - if: github.event_name == 'push' - steps: - - uses: actions/checkout@v1 - - - name: install nuget - uses: NuGet/setup-nuget@v1 - - - name: Enable long file paths - run: git config --global core.longpaths true - - - name: Update submodules - run: git submodule -q update --init --recursive - - - name: Build - shell: pwsh - run: | - $DebugPreference = "Continue" - ./build.ps1 - - - name: Publish to nightly feed -myget - if: success() - run: nuget.exe push .\artifacts\*.nupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v2/package - # TODO: if github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org + # runs-on: windows-latest + # needs: [Build] + # if: github.event_name == 'push' + # steps: + # - uses: actions/checkout@v1 + # - name: install nuget + # uses: NuGet/setup-nuget@v1 + # - name: Enable long file paths + # run: git config --global core.longpaths true + # - name: Update submodules + # run: git submodule -q update --init --recursive + # - name: Build + # shell: pwsh + # run: | + # $DebugPreference = "Continue" + # ./build.ps1 + # - name: Publish to nightly feed -myget + # if: success() + # run: nuget.exe push .\artifacts\*.nupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v2/package + # TODO: if github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org From a1d2e6f888f70e5ed069a05301e89d1549db3b28 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 12:46:52 +1100 Subject: [PATCH 05/53] Remove old xunit reference --- Directory.Build.targets | 2 +- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index 71dd9ab99a..82712c3f89 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -35,7 +35,7 @@ - + diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 1c909faab6..842582c2f8 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -18,7 +18,6 @@ - From fc6ac75b9b4c937758c73b0e1286432b1d2498da Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 12:59:14 +1100 Subject: [PATCH 06/53] Debug framework skipping --- build.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/build.ps1 b/build.ps1 index e2c62c3d37..94580c0918 100644 --- a/build.ps1 +++ b/build.ps1 @@ -12,6 +12,7 @@ $skipFullFramework = 'false' # If we are trying to build only netcoreapp versions for testings then skip building the full framework targets if ("$targetFramework".StartsWith("netcoreapp")) { + Write-Debug "Skipping Full Framework" $skipFullFramework = 'true' } From df66a98f5f35f75e4d71884277dbc029f0b57548 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 13:09:02 +1100 Subject: [PATCH 07/53] Skip linux for testing --- .github/workflows/build-and-test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 3869517f96..723128d45e 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -15,10 +15,10 @@ jobs: strategy: matrix: opts: - - os: ubuntu-latest - framework: netcoreapp2.1 - runtime: linux-x64 - cover: False + # - os: ubuntu-latest + # framework: netcoreapp2.1 + # runtime: linux-x64 + # cover: False - os: windows-latest framework: netcoreapp2.1 runtime: win-x64 From 60ab03b73a2a528975dc04f5427950218cacf838 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 13:19:23 +1100 Subject: [PATCH 08/53] Update build-and-test.yml --- .github/workflows/build-and-test.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 723128d45e..dc67f6c38f 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -14,7 +14,7 @@ jobs: Build: strategy: matrix: - opts: + options: # - os: ubuntu-latest # framework: netcoreapp2.1 # runtime: linux-x64 @@ -32,7 +32,7 @@ jobs: runtime: win-x86 cover: False - runs-on: ${{ matrix.opts.os }} + runs-on: ${{ matrix.options.os }} steps: - uses: actions/checkout@v1 @@ -52,19 +52,19 @@ jobs: shell: pwsh run: | $DebugPreference = "Continue" - ./build.ps1 "${{matrix.opts.framework}}" + ./build.ps1 "${{matrix.options.framework}}" - name: Test no Coverage - if: matrix.opts.cover != 'True' + if: matrix.options.cover != 'True' run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opt.framework}}" -r "${{matrix.opt.runtime}}" --no-build --filter Sandbox - name: Test with Coverage - if: matrix.opts.cover == 'True' + if: matrix.options.cover == 'True' run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opt.framework}}" -r "${{matrix.opt.runtime}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover - name: Update Codecov uses: iansu/codecov-action-node@v1.0.0 - if: matrix.opts.cover == 'True' + if: matrix.options.cover == 'True' with: token: ${{secrets.CODECOV_TOKEN}} file: "coverage.xml" From 92e5d5c4b455db578208bdf403c80b06d2bec5b9 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 13:31:05 +1100 Subject: [PATCH 09/53] Use pwsh for scripts --- .github/workflows/build-and-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index dc67f6c38f..9dd66e11a2 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -56,10 +56,12 @@ jobs: - name: Test no Coverage if: matrix.options.cover != 'True' + shell: pwsh run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opt.framework}}" -r "${{matrix.opt.runtime}}" --no-build --filter Sandbox - name: Test with Coverage if: matrix.options.cover == 'True' + shell: pwsh run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opt.framework}}" -r "${{matrix.opt.runtime}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover - name: Update Codecov From 44733d3fa9f25a7a0717f5442cb809042e8383d9 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 13:43:23 +1100 Subject: [PATCH 10/53] Fix options naming --- .github/workflows/build-and-test.yml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 9dd66e11a2..438daa402c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -14,7 +14,7 @@ jobs: Build: strategy: matrix: - options: + opts: # - os: ubuntu-latest # framework: netcoreapp2.1 # runtime: linux-x64 @@ -32,7 +32,7 @@ jobs: runtime: win-x86 cover: False - runs-on: ${{ matrix.options.os }} + runs-on: ${{ matrix.opts.os }} steps: - uses: actions/checkout@v1 @@ -52,21 +52,19 @@ jobs: shell: pwsh run: | $DebugPreference = "Continue" - ./build.ps1 "${{matrix.options.framework}}" + ./build.ps1 "${{matrix.opts.framework}}" - name: Test no Coverage - if: matrix.options.cover != 'True' - shell: pwsh - run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opt.framework}}" -r "${{matrix.opt.runtime}}" --no-build --filter Sandbox + if: matrix.opts.cover != True + run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}}" -r "${{matrix.opts.runtime}}" --no-build --filter Sandbox - name: Test with Coverage - if: matrix.options.cover == 'True' - shell: pwsh - run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opt.framework}}" -r "${{matrix.opt.runtime}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover + if: matrix.opts.cover == True + run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}} -r "${{matrix.opts.runtime}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover - name: Update Codecov uses: iansu/codecov-action-node@v1.0.0 - if: matrix.options.cover == 'True' + if: matrix.opts.cover == True with: token: ${{secrets.CODECOV_TOKEN}} file: "coverage.xml" From 69f3d184a4fd7eff9e32ba4a7c45cd5a3e507c79 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 13:52:01 +1100 Subject: [PATCH 11/53] Fix booleans? --- .github/workflows/build-and-test.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 438daa402c..0ed8760f0b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -18,19 +18,19 @@ jobs: # - os: ubuntu-latest # framework: netcoreapp2.1 # runtime: linux-x64 - # cover: False + # cover: false - os: windows-latest framework: netcoreapp2.1 runtime: win-x64 - cover: True + cover: true - os: windows-latest framework: net472 runtime: win-x64 - cover: False + cover: false - os: windows-latest framework: net472 runtime: win-x86 - cover: False + cover: false runs-on: ${{ matrix.opts.os }} @@ -55,16 +55,16 @@ jobs: ./build.ps1 "${{matrix.opts.framework}}" - name: Test no Coverage - if: matrix.opts.cover != True + if: matrix.opts.cover == 'false' run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}}" -r "${{matrix.opts.runtime}}" --no-build --filter Sandbox - name: Test with Coverage - if: matrix.opts.cover == True + if: matrix.opts.cover == 'true' run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}} -r "${{matrix.opts.runtime}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover - name: Update Codecov uses: iansu/codecov-action-node@v1.0.0 - if: matrix.opts.cover == True + if: matrix.opts.cover == 'true' with: token: ${{secrets.CODECOV_TOKEN}} file: "coverage.xml" From 3337d2dee8e5959d70a06ff444a9aecf08fc0718 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 14:06:49 +1100 Subject: [PATCH 12/53] Conditionals are hard. --- .github/workflows/build-and-test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 0ed8760f0b..9c15ff254b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -55,16 +55,16 @@ jobs: ./build.ps1 "${{matrix.opts.framework}}" - name: Test no Coverage - if: matrix.opts.cover == 'false' + if: ${{matrix.opts.cover}} == 'false' run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}}" -r "${{matrix.opts.runtime}}" --no-build --filter Sandbox - name: Test with Coverage - if: matrix.opts.cover == 'true' + if: ${{matrix.opts.cover}} == 'true' run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}} -r "${{matrix.opts.runtime}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover - name: Update Codecov uses: iansu/codecov-action-node@v1.0.0 - if: matrix.opts.cover == 'true' + if: ${{matrix.opts.cover}} == 'true' with: token: ${{secrets.CODECOV_TOKEN}} file: "coverage.xml" From 3755f88ab2c08619587d3e43a00bb88c1c6e5b5b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 14:10:52 +1100 Subject: [PATCH 13/53] Update build-and-test.yml --- .github/workflows/build-and-test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 9c15ff254b..7318eb7884 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -55,16 +55,16 @@ jobs: ./build.ps1 "${{matrix.opts.framework}}" - name: Test no Coverage - if: ${{matrix.opts.cover}} == 'false' + if: matrix.opts.cover == false run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}}" -r "${{matrix.opts.runtime}}" --no-build --filter Sandbox - name: Test with Coverage - if: ${{matrix.opts.cover}} == 'true' + if: matrix.opts.cover == true run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}} -r "${{matrix.opts.runtime}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover - name: Update Codecov uses: iansu/codecov-action-node@v1.0.0 - if: ${{matrix.opts.cover}} == 'true' + if: matrix.opts.cover == true with: token: ${{secrets.CODECOV_TOKEN}} file: "coverage.xml" From c7fdf1a5a2981b6adc1851d22a6c1685143dd601 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 14:16:06 +1100 Subject: [PATCH 14/53] Fix missing quote --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 7318eb7884..aa02954fe4 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -60,7 +60,7 @@ jobs: - name: Test with Coverage if: matrix.opts.cover == true - run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}} -r "${{matrix.opts.runtime}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover + run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}}" -r "${{matrix.opts.runtime}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover - name: Update Codecov uses: iansu/codecov-action-node@v1.0.0 From e2f090aea811f6945b0e02b169dbca169475cbc3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 15:46:07 +1100 Subject: [PATCH 15/53] Update build-and-test.yml --- .github/workflows/build-and-test.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index aa02954fe4..9b26d790ae 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -17,19 +17,19 @@ jobs: opts: # - os: ubuntu-latest # framework: netcoreapp2.1 - # runtime: linux-x64 + # runtime: x64 # cover: false - os: windows-latest framework: netcoreapp2.1 - runtime: win-x64 + runtime: x64 # Not currently used. See https://github.com/actions/setup-dotnet/issues/72 cover: true - os: windows-latest framework: net472 - runtime: win-x64 + runtime: x64 cover: false - os: windows-latest framework: net472 - runtime: win-x86 + runtime: x86 cover: false runs-on: ${{ matrix.opts.os }} @@ -56,11 +56,11 @@ jobs: - name: Test no Coverage if: matrix.opts.cover == false - run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}}" -r "${{matrix.opts.runtime}}" --no-build --filter Sandbox + run: C:\Program Files\dotnet\sdk\ dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}}" --no-build --filter Sandbox - name: Test with Coverage if: matrix.opts.cover == true - run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}}" -r "${{matrix.opts.runtime}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover + run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover - name: Update Codecov uses: iansu/codecov-action-node@v1.0.0 From abde989660ef2789fc2df95f0a9aa80b0d5fdda4 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 15:56:58 +1100 Subject: [PATCH 16/53] Fix tests --- .github/workflows/build-and-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 9b26d790ae..06627c1396 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -56,11 +56,11 @@ jobs: - name: Test no Coverage if: matrix.opts.cover == false - run: C:\Program Files\dotnet\sdk\ dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}}" --no-build --filter Sandbox + run: dotnet test -c Release -f "${{matrix.opts.framework}}" --no-build --filter Sandbox - name: Test with Coverage if: matrix.opts.cover == true - run: dotnet test **/*tests/*.csproj -c Release -f "${{matrix.opts.framework}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover + run: dotnet test -c Release -f "${{matrix.opts.framework}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover - name: Update Codecov uses: iansu/codecov-action-node@v1.0.0 From f7e62adcab29f2c2f4c433d0f5f81c025eff2722 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 23:08:25 +1100 Subject: [PATCH 17/53] Combine xunit and test for converage --- .github/workflows/build-and-test.yml | 38 ++++--- Directory.Build.targets | 21 ++-- build.cmd | 17 --- build.ps1 | 28 +++-- run-tests.ps1 | 101 ------------------ src/ImageSharp/ImageSharp.csproj | 2 - test.ps1 | 34 ++++++ tests/Directory.Build.props | 3 +- tests/Directory.Build.targets | 16 ++- .../ImageSharp.Benchmarks.csproj | 4 +- .../ImageSharp.Sandbox46.csproj | 6 +- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 13 ++- 12 files changed, 106 insertions(+), 177 deletions(-) delete mode 100644 build.cmd delete mode 100644 run-tests.ps1 create mode 100644 test.ps1 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 06627c1396..ca28dda988 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -14,25 +14,25 @@ jobs: Build: strategy: matrix: - opts: + options: # - os: ubuntu-latest # framework: netcoreapp2.1 - # runtime: x64 - # cover: false + # runtime: -x64 + # codecov: false - os: windows-latest framework: netcoreapp2.1 - runtime: x64 # Not currently used. See https://github.com/actions/setup-dotnet/issues/72 - cover: true + runtime: -x64 + codecov: true - os: windows-latest framework: net472 - runtime: x64 - cover: false + runtime: -x64 + codecov: false - os: windows-latest framework: net472 - runtime: x86 - cover: false + runtime: -x86 + codecov: false - runs-on: ${{ matrix.opts.os }} + runs-on: ${{ matrix.options.os }} steps: - uses: actions/checkout@v1 @@ -52,22 +52,20 @@ jobs: shell: pwsh run: | $DebugPreference = "Continue" - ./build.ps1 "${{matrix.opts.framework}}" + ./build.ps1 "${{matrix.options.framework}}" - - name: Test no Coverage - if: matrix.opts.cover == false - run: dotnet test -c Release -f "${{matrix.opts.framework}}" --no-build --filter Sandbox - - - name: Test with Coverage - if: matrix.opts.cover == true - run: dotnet test -c Release -f "${{matrix.opts.framework}}" --no-build --filter Sandbox /p:CollectCoverage=true /p:CoverletOutputFormat=opencover + - name: Test + shell: pwsh + run: ./test.ps1 "${{ matrix.options.os }}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}" + env: + XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit - name: Update Codecov uses: iansu/codecov-action-node@v1.0.0 - if: matrix.opts.cover == true + if: matrix.options.cover == true with: token: ${{secrets.CODECOV_TOKEN}} - file: "coverage.xml" + file: "coverage.${{matrix.options.framework}}.xml" flags: unittests # Publish: # runs-on: windows-latest diff --git a/Directory.Build.targets b/Directory.Build.targets index 82712c3f89..349ee4b3d7 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -15,6 +15,13 @@ $(DefineConstants);$(OS) + + + + + + + @@ -31,19 +38,7 @@ - - - - - - - - - - - - - + diff --git a/build.cmd b/build.cmd deleted file mode 100644 index 6372b41253..0000000000 --- a/build.cmd +++ /dev/null @@ -1,17 +0,0 @@ -@echo Off - -PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '.\build.ps1'" - -if not "%errorlevel%"=="0" goto failure - -:success -ECHO successfully built project -REM exit 0 -goto end - -:failure -ECHO failed to build. -REM exit -1 -goto end - -:end \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 94580c0918..07920aca1f 100644 --- a/build.ps1 +++ b/build.ps1 @@ -8,14 +8,6 @@ $version = '' $tagRegex = '^v?(\d+\.\d+\.\d+)(?:-([a-zA-Z]+)\.?(\d*))?$' -$skipFullFramework = 'false' - -# If we are trying to build only netcoreapp versions for testings then skip building the full framework targets -if ("$targetFramework".StartsWith("netcoreapp")) { - Write-Debug "Skipping Full Framework" - $skipFullFramework = 'true' -} - function ToBuildNumber { param( $date ) @@ -99,7 +91,7 @@ else { Write-Debug "Discovered base version from tags '${version}'" } - # Create a build number based on the current time. + # Create a build number based on the current datetime. $buildNumber = "" if ( "$env:GITHUB_SHA" -ne '') { @@ -133,20 +125,26 @@ else { } Write-Host "Building version '${version}'" -dotnet restore /p:packageversion=$version /p:DisableImplicitNuGetFallbackFolder=true /p:skipFullFramework=$skipFullFramework -$repositoryUrl = "https://github.com/SixLabors/" +if ($targetFramework -ne 'ALL') { + $targetFramework = "-f $targetFramework" +} + +dotnet restore $targetFramework /p:packageversion=$version /p:DisableImplicitNuGetFallbackFolder=true + +$repositoryUrl = "" if ("$env:GITHUB_REPOSITORY" -ne "") { $repositoryUrl = "https://github.com/$env:GITHUB_REPOSITORY" } Write-Host "Building projects" -dotnet build -c Release /p:packageversion=$version /p:skipFullFramework=$skipFullFramework /p:RepositoryUrl=$repositoryUrl + +dotnet build -c Release $targetFramework /p:packageversion=$version /p:RepositoryUrl=$repositoryUrl if ($LASTEXITCODE ) { Exit $LASTEXITCODE } -Write-Host "Packaging projects" +# Write-Host "Packaging projects" -dotnet pack -c Release --output "$PSScriptRoot/artifacts" --no-build /p:packageversion=$version /p:skipFullFramework=$skipFullFramework /p:RepositoryUrl=$repositoryUrl -if ($LASTEXITCODE ) { Exit $LASTEXITCODE } +# dotnet pack -c Release --output "$PSScriptRoot/artifacts" --no-build /p:packageversion=$version /p:skipFullFramework=$skipFullFramework /p:RepositoryUrl=$repositoryUrl +# if ($LASTEXITCODE ) { Exit $LASTEXITCODE } diff --git a/run-tests.ps1 b/run-tests.ps1 deleted file mode 100644 index c356495440..0000000000 --- a/run-tests.ps1 +++ /dev/null @@ -1,101 +0,0 @@ -param( - [string]$os, - [string]$targetFramework, - [string]$doCoverage = "False", - [string]$is32Bit = "False" -) - -if (!$os) { - Write-Host "run-tests.ps1 ERROR: os is undefined!" - exit 1 -} - -if (!$targetFramework) { - Write-Host "run-tests.ps1 ERROR: targetFramework is undefined!" - exit 1 -} - -function VerifyPath($path, $errorMessage) { - if (!(Test-Path -Path $path)) { - Write-Host "run-tests.ps1 $errorMessage `n $xunitRunnerPath" - exit 1 - } -} - -function CheckSubmoduleStatus() { - $submoduleStatus = (git submodule status) | Out-String - # if the result string is empty, the command failed to run (we didn't capture the error stream) - if ($submoduleStatus) { - # git has been called successfully, what about the status? - if (($submoduleStatus -match "\-") -or ($submoduleStatus -match "\(\(null\)\)")) { - # submodule has not been initialized! - return 2; - } - elseif ($submoduleStatus -match "\+") { - # submodule is not synced: - return 1; - } - else { - # everything fine: - return 0; - } - } - else { - # git call failed, so we should warn - return 3; - } -} - -if (($os -eq "windows-latest") -and ($doCoverage -eq "True") -and ($env:CI -eq "True") -and ($is32Bit -ne "True")) { - # We execute CodeCoverage.cmd only for one specific job on CI (windows + coverageTargetFramework + 64bit ) - $testRunnerCmd = ".\tests\CodeCoverage\CodeCoverage.cmd" -} -else { - Set-Location .\tests - $xunitArgs = "-nobuild -c Release -framework $targetFramework" - - $coreTargetFrameworkRegex = '^netcoreapp(\d+\.\d+)$' - if ($targetFramework -match $coreTargetFrameworkRegex) { - # There were issues matching the correct installed runtime if we do not specify it explicitly: - $fxVersion = $matches[1] + ".0" - $xunitArgs += " --fx-version $fxVersion" - } - - if ($is32Bit -eq "True") { - $xunitArgs += " -x86" - } - - $testRunnerCmd = "dotnet xunit $xunitArgs" -} - -Write-Host "running:" -Write-Host $testRunnerCmd -Write-Host "..." - -Invoke-Expression $testRunnerCmd - -Set-Location $PSScriptRoot - -$exitCodeOfTests = $LASTEXITCODE; - -if (0 -ne ([int]$exitCodeOfTests)) { - # check submodule status - $submoduleStatus = CheckSubmoduleStatus - if ([int]$submoduleStatus -eq 1) { - # not synced - Write-Host -ForegroundColor Yellow "Check if submodules are up to date. You can use 'git submodule update' to fix this"; - } - elseif ($submoduleStatus -eq 2) { - # not initialized - Write-Host -ForegroundColor Yellow "Check if submodules are initialized. You can run 'git submodule init' to initialize them." - } - elseif ($submoduleStatus -eq 3) { - # git not found, maybe submodules not synced? - Write-Host -ForegroundColor Yellow "Could not check if submodules are initialized correctly. Maybe git is not installed?" - } - else { - #Write-Host "Submodules are up to date"; - } -} - -exit $exitCodeOfTests diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 8ca1f2ba5e..4d354d3cca 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -10,8 +10,6 @@ $(packageversion) 0.0.1 - netcoreapp2.1;netstandard1.3;netstandard2.0 - $(TargetFrameworks);net472 netcoreapp2.1;netstandard2.0;netstandard1.3;net472 true diff --git a/test.ps1 b/test.ps1 new file mode 100644 index 0000000000..ebee0a7f03 --- /dev/null +++ b/test.ps1 @@ -0,0 +1,34 @@ +param( + [Parameter(Mandatory, Position = 0)] + [string]$os, + [Parameter(Mandatory, Position = 1)] + [string]$targetFramework, + [Parameter(Mandatory, Position = 2)] + [string]$platform, + [Parameter(Mandatory, Position = 3)] + [bool]$codecov +) + +if ($codecov -eq $TRUE) { + + # xunit doesn't understand the CollectCoverage params + dotnet clean -c Debug + dotnet test -c Debug -f $targetFramework /p:codecov=true /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput='../../../coverage.xml' +} +else { + + # There were issues matching the correct installed runtime if we do not specify it explicitly: + # https://github.com/xunit/xunit/issues/1476 + # This fix assumes the base version is installed. + $coreTargetFrameworkRegex = '^netcoreapp(\d+\.\d+)$' + if ($targetFramework -match $coreTargetFrameworkRegex) { + $fxVersion = "--fx-version ${matches[1]}.0" + } + + Set-Location $env:XUNIT_PATH + + dotnet clean -c Release + dotnet xunit -c Release -f $targetFramework $fxVersion $platform + + Set-Location $PSScriptRoot +} diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 9c6fdae3d3..48ffbf315a 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -26,7 +26,8 @@ - + diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets index f8a4936e23..f7b70fe94e 100644 --- a/tests/Directory.Build.targets +++ b/tests/Directory.Build.targets @@ -15,5 +15,19 @@ - + + + + + + + + + + + + + + + diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index a25b548f2b..bac4ad71c3 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -5,9 +5,9 @@ ImageSharp.Benchmarks Exe SixLabors.ImageSharp.Benchmarks - netcoreapp2.1 - $(TargetFrameworks);net472 + netcoreapp2.1;net472 false + false diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index f7959df6af..289d2d8508 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -8,9 +8,9 @@ false SixLabors.ImageSharp.Sandbox46 win7-x64 - netcoreapp2.1 - $(TargetFrameworks);net472 + netcoreapp2.1;net472 SixLabors.ImageSharp.Sandbox46.Program + false @@ -22,5 +22,5 @@ - + diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 842582c2f8..6a78ef21e3 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -2,8 +2,7 @@ - netcoreapp2.1 - $(TargetFrameworks);net462;net472 + netcoreapp2.1;net462;net472 True latest full @@ -12,12 +11,22 @@ SixLabors.ImageSharp.Tests AnyCPU;x64;x86 SixLabors.ImageSharp.Tests + + + true + + + + + + + From 22661f09ceb242e7cf5ac4fc1ba9d99492d99415 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 23:15:47 +1100 Subject: [PATCH 18/53] dotnet restore is implicit in core sdk 2+ --- build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.ps1 b/build.ps1 index 07920aca1f..3389c4cc89 100644 --- a/build.ps1 +++ b/build.ps1 @@ -130,7 +130,7 @@ if ($targetFramework -ne 'ALL') { $targetFramework = "-f $targetFramework" } -dotnet restore $targetFramework /p:packageversion=$version /p:DisableImplicitNuGetFallbackFolder=true +# dotnet restore $targetFramework /p:packageversion=$version /p:DisableImplicitNuGetFallbackFolder=true $repositoryUrl = "" From f2162a7c3f0cc44e8046315e65e324415bf4b154 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 23:25:05 +1100 Subject: [PATCH 19/53] Update build.ps1 --- build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.ps1 b/build.ps1 index 3389c4cc89..fd7ac61908 100644 --- a/build.ps1 +++ b/build.ps1 @@ -140,7 +140,7 @@ if ("$env:GITHUB_REPOSITORY" -ne "") { Write-Host "Building projects" -dotnet build -c Release $targetFramework /p:packageversion=$version /p:RepositoryUrl=$repositoryUrl +dotnet build -c Release ${$targetFramework} /p:packageversion=$version /p:RepositoryUrl=$repositoryUrl if ($LASTEXITCODE ) { Exit $LASTEXITCODE } From 30dc32aba8c989366c1f093f12c92bc97d6fbe8b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 23:34:03 +1100 Subject: [PATCH 20/53] Try passing variable as bool --- .github/workflows/build-and-test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index ca28dda988..4cee82237b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -18,19 +18,19 @@ jobs: # - os: ubuntu-latest # framework: netcoreapp2.1 # runtime: -x64 - # codecov: false + # codecov: $false - os: windows-latest framework: netcoreapp2.1 runtime: -x64 - codecov: true + codecov: $true - os: windows-latest framework: net472 runtime: -x64 - codecov: false + codecov: $false - os: windows-latest framework: net472 runtime: -x86 - codecov: false + codecov: $false runs-on: ${{ matrix.options.os }} From 932673da8790d1fad840d65a942c32cdcad9777d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 23:35:46 +1100 Subject: [PATCH 21/53] Update test.ps1 --- test.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.ps1 b/test.ps1 index ebee0a7f03..82c3021d20 100644 --- a/test.ps1 +++ b/test.ps1 @@ -28,7 +28,7 @@ else { Set-Location $env:XUNIT_PATH dotnet clean -c Release - dotnet xunit -c Release -f $targetFramework $fxVersion $platform + dotnet xunit -c Release -f $targetFramework ${fxVersion} $platform Set-Location $PSScriptRoot } From b3430926be17958df93a560b42a2b26902459b67 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 23:41:42 +1100 Subject: [PATCH 22/53] Use strings --- .github/workflows/build-and-test.yml | 8 ++++---- test.ps1 | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 4cee82237b..ca28dda988 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -18,19 +18,19 @@ jobs: # - os: ubuntu-latest # framework: netcoreapp2.1 # runtime: -x64 - # codecov: $false + # codecov: false - os: windows-latest framework: netcoreapp2.1 runtime: -x64 - codecov: $true + codecov: true - os: windows-latest framework: net472 runtime: -x64 - codecov: $false + codecov: false - os: windows-latest framework: net472 runtime: -x86 - codecov: $false + codecov: false runs-on: ${{ matrix.options.os }} diff --git a/test.ps1 b/test.ps1 index 82c3021d20..eace163236 100644 --- a/test.ps1 +++ b/test.ps1 @@ -6,10 +6,10 @@ param( [Parameter(Mandatory, Position = 2)] [string]$platform, [Parameter(Mandatory, Position = 3)] - [bool]$codecov + [string]$codecov ) -if ($codecov -eq $TRUE) { +if ($codecov -eq 'true') { # xunit doesn't understand the CollectCoverage params dotnet clean -c Debug From d8610f43f849e9f81a5093e7da5398974d3bf2fe Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Jan 2020 23:57:09 +1100 Subject: [PATCH 23/53] Update test.ps1 --- test.ps1 | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test.ps1 b/test.ps1 index eace163236..307d00469a 100644 --- a/test.ps1 +++ b/test.ps1 @@ -11,7 +11,9 @@ param( if ($codecov -eq 'true') { - # xunit doesn't understand the CollectCoverage params + # xunit doesn't understand the CollectCoverage params so use dotnet test + # Coverage tests are run in debug because the coverage tools are triggering a JIT error in filter processors + # that causes the blue component of transformed values to be corrupted. dotnet clean -c Debug dotnet test -c Debug -f $targetFramework /p:codecov=true /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput='../../../coverage.xml' } @@ -25,8 +27,14 @@ else { $fxVersion = "--fx-version ${matches[1]}.0" } + # xunit requires explicit path Set-Location $env:XUNIT_PATH + # xunit doesn't actually understand -x64 as an option + if ($platform -ne '-x86') { + $platform = '' + } + dotnet clean -c Release dotnet xunit -c Release -f $targetFramework ${fxVersion} $platform From fa051190dda0fc0fb81e538c9e9d83ef95e3bb8c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 00:12:03 +1100 Subject: [PATCH 24/53] Update PngEncoderTests.cs --- tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index d3e675b907..41576cc0df 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -200,6 +200,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void PaletteColorType_WuQuantizer(TestImageProvider provider, int paletteSize) where TPixel : struct, IPixel { + // TODO: Investigate WuQuantizer to see if we can reduce memory pressure. + if (!TestEnvironment.Is64BitProcess) + { + return; + } + foreach (PngInterlaceMode interlaceMode in InterlaceMode) { TestPngEncoderCore( From 194e9abef975a814faad3e1d3c97843b646270dc Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 00:31:14 +1100 Subject: [PATCH 25/53] Fix codecov condition --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index ca28dda988..1383737425 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -62,7 +62,7 @@ jobs: - name: Update Codecov uses: iansu/codecov-action-node@v1.0.0 - if: matrix.options.cover == true + if: matrix.options.codecov == true with: token: ${{secrets.CODECOV_TOKEN}} file: "coverage.${{matrix.options.framework}}.xml" From 15244d39470c8066d68d59f6b7d7a0e6cdd1aa1a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 08:16:58 +1100 Subject: [PATCH 26/53] Use targets. Coverage should now upload --- Directory.Build.props | 9 ------- Directory.Build.targets | 7 ----- ImageSharp.sln | 7 ----- src/Directory.Build.props | 4 +++ test.ps1 | 4 +-- tests/Directory.Build.targets | 27 +++++++++++++++++-- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 12 +++------ 7 files changed, 34 insertions(+), 36 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 95cadcd57f..c8c0fe6f92 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -61,15 +61,6 @@ $(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS - - true - - - - - false - - Six Labors and contributors diff --git a/Directory.Build.targets b/Directory.Build.targets index 349ee4b3d7..f6f852b93e 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -14,13 +14,6 @@ $(DefineConstants);$(OS) - - - - - - - diff --git a/ImageSharp.sln b/ImageSharp.sln index 6a80589d8f..eb6c617d09 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -51,12 +51,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{56801022 tests\Directory.Build.targets = tests\Directory.Build.targets EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodeCoverage", "CodeCoverage", "{D4C5EC58-F8E6-4636-B9EE-C99D2578E5C6}" - ProjectSection(SolutionItems) = preProject - tests\CodeCoverage\CodeCoverage.cmd = tests\CodeCoverage\CodeCoverage.cmd - tests\CodeCoverage\packages.config = tests\CodeCoverage\packages.config - EndProjectSection -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Images", "Images", "{FA55F5DE-11A6-487D-ABA4-BC93A02717DD}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Input", "Input", "{9DA226A1-8656-49A8-A58A-A8B5C081AD66}" @@ -405,7 +399,6 @@ Global GlobalSection(NestedProjects) = preSolution {FBE8C1AD-5AEC-4514-9B64-091D8E145865} = {1799C43E-5C54-4A8F-8D64-B1475241DB0D} {2AA31A1F-142C-43F4-8687-09ABCA4B3A26} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} - {D4C5EC58-F8E6-4636-B9EE-C99D2578E5C6} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {FA55F5DE-11A6-487D-ABA4-BC93A02717DD} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {9DA226A1-8656-49A8-A58A-A8B5C081AD66} = {FA55F5DE-11A6-487D-ABA4-BC93A02717DD} {1A82C5F6-90E0-4E97-BE16-A825C046B493} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66} diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 6fbbb7c916..e94848675f 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -22,6 +22,10 @@ true + + true + + diff --git a/test.ps1 b/test.ps1 index 307d00469a..61995ca7f6 100644 --- a/test.ps1 +++ b/test.ps1 @@ -11,11 +11,11 @@ param( if ($codecov -eq 'true') { - # xunit doesn't understand the CollectCoverage params so use dotnet test + # xunit doesn't understand custom params so use dotnet test # Coverage tests are run in debug because the coverage tools are triggering a JIT error in filter processors # that causes the blue component of transformed values to be corrupted. dotnet clean -c Debug - dotnet test -c Debug -f $targetFramework /p:codecov=true /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput='../../../coverage.xml' + dotnet test -c Debug -f $targetFramework /p:codecov=true } else { diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets index f7b70fe94e..5c8f45e26b 100644 --- a/tests/Directory.Build.targets +++ b/tests/Directory.Build.targets @@ -15,11 +15,34 @@ - + + + + + + + + + + + + full + true + true + opencover + + $(MSBuildThisFileDirectory)..\coverage.xml + + + true + + + + @@ -29,5 +52,5 @@ - + diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 6a78ef21e3..d09ab9d0b3 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -5,28 +5,22 @@ netcoreapp2.1;net462;net472 True latest - full - portable True SixLabors.ImageSharp.Tests AnyCPU;x64;x86 SixLabors.ImageSharp.Tests - - - true - + + + - - - From 2bf586a84397b88b98286d626a47d5183a9efa2e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 09:56:13 +1100 Subject: [PATCH 27/53] Enable ubuntu --- .github/workflows/build-and-test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 1383737425..d18299aa43 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -15,10 +15,10 @@ jobs: strategy: matrix: options: - # - os: ubuntu-latest - # framework: netcoreapp2.1 - # runtime: -x64 - # codecov: false + - os: ubuntu-latest + framework: netcoreapp2.1 + runtime: -x64 + codecov: false - os: windows-latest framework: netcoreapp2.1 runtime: -x64 From 3f8fa7ce201dd81143e2c335393e09b913f15803 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 10:21:14 +1100 Subject: [PATCH 28/53] Add targeting pack for linux --- Directory.Build.props | 1 + Directory.Build.targets | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index c8c0fe6f92..f961ae881e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -99,6 +99,7 @@ + diff --git a/Directory.Build.targets b/Directory.Build.targets index f6f852b93e..1d158eccef 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -14,11 +14,12 @@ $(DefineConstants);$(OS) - + + @@ -31,7 +32,7 @@ - + From 3c6bad3e0ab17a7306cd7c1595bce4c6e2ff553d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 10:49:54 +1100 Subject: [PATCH 29/53] Use dotnet test on linux --- test.ps1 | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/test.ps1 b/test.ps1 index 61995ca7f6..c45074329f 100644 --- a/test.ps1 +++ b/test.ps1 @@ -11,15 +11,19 @@ param( if ($codecov -eq 'true') { - # xunit doesn't understand custom params so use dotnet test + # xunit doesn't understand custom params so use dotnet test. # Coverage tests are run in debug because the coverage tools are triggering a JIT error in filter processors # that causes the blue component of transformed values to be corrupted. dotnet clean -c Debug dotnet test -c Debug -f $targetFramework /p:codecov=true } +elseif ($os -ne 'windows-latest') { + # xunit doesn't run without mono on linux and macos. + dotnet test --no-build -c Release -f $targetFramework +} else { - # There were issues matching the correct installed runtime if we do not specify it explicitly: + # xunit has issues matching the correct installed runtime if we do not specify it explicitly. # https://github.com/xunit/xunit/issues/1476 # This fix assumes the base version is installed. $coreTargetFrameworkRegex = '^netcoreapp(\d+\.\d+)$' @@ -27,16 +31,15 @@ else { $fxVersion = "--fx-version ${matches[1]}.0" } - # xunit requires explicit path + # xunit requires explicit path. Set-Location $env:XUNIT_PATH - # xunit doesn't actually understand -x64 as an option + # xunit doesn't actually understand -x64 as an option. if ($platform -ne '-x86') { $platform = '' } - dotnet clean -c Release - dotnet xunit -c Release -f $targetFramework ${fxVersion} $platform + dotnet xunit --no-build -c Release -f $targetFramework ${fxVersion} $platform Set-Location $PSScriptRoot } From 6dad4b5baa93ab92eda07c9f305fe879f65eff8e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 13:19:36 +1100 Subject: [PATCH 30/53] GitVersion experiment --- .github/workflows/build-and-test.yml | 88 ++++++++++++++++++++++------ gitversion.yml | 6 ++ 2 files changed, 75 insertions(+), 19 deletions(-) create mode 100644 gitversion.yml diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index d18299aa43..ffee25a66c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -19,18 +19,18 @@ jobs: framework: netcoreapp2.1 runtime: -x64 codecov: false - - os: windows-latest - framework: netcoreapp2.1 - runtime: -x64 - codecov: true - - os: windows-latest - framework: net472 - runtime: -x64 - codecov: false - - os: windows-latest - framework: net472 - runtime: -x86 - codecov: false + # - os: windows-latest + # framework: netcoreapp2.1 + # runtime: -x64 + # codecov: true + # - os: windows-latest + # framework: net472 + # runtime: -x64 + # codecov: false + # - os: windows-latest + # framework: net472 + # runtime: -x86 + # codecov: false runs-on: ${{ matrix.options.os }} @@ -40,19 +40,69 @@ jobs: - name: Install nuget uses: NuGet/setup-nuget@v1 - - name: Enable long file paths + - name: Setup Git run: | git config --global core.autocrlf false git config --global core.longpaths true + git fetch --prune --unshallow + git submodule -q update --init --recursive + + - name: Fetch tags for GitVersion + run: | + git fetch --tags - - name: Update Submodules - run: git submodule -q update --init --recursive + - name: Fetch master for GitVersion + if: github.ref != 'refs/heads/master' + run: git branch --create-reflog master origin/master + + - name: Install GitVersion + uses: gittools/actions/setup-gitversion@v0.3 + with: + versionSpec: "5.1.x" + + - name: Use GitVersion + id: gitversion # step id used as reference for output values + uses: gittools/actions/execute-gitversion@v0.3 + - run: | + echo "Major: ${{ steps.gitversion.outputs.major }}" + echo "Minor: ${{ steps.gitversion.outputs.minor }}" + echo "Patch: ${{ steps.gitversion.outputs.patch }}" + echo "PreReleaseTag: ${{ steps.gitversion.outputs.preReleaseTag }}" + echo "PreReleaseTagWithDash: ${{ steps.gitversion.outputs.preReleaseTagWithDash }}" + echo "PreReleaseLabel: ${{ steps.gitversion.outputs.preReleaseLabel }}" + echo "PreReleaseNumber: ${{ steps.gitversion.outputs.preReleaseNumber }}" + echo "WeightedPreReleaseNumber: ${{ steps.gitversion.outputs.weightedPreReleaseNumber }}" + echo "BuildMetaData: ${{ steps.gitversion.outputs.buildMetaData }}" + echo "BuildMetaDataPadded: ${{ steps.gitversion.outputs.buildMetaDataPadded }}" + echo "FullBuildMetaData: ${{ steps.gitversion.outputs.fullBuildMetaData }}" + echo "MajorMinorPatch: ${{ steps.gitversion.outputs.majorMinorPatch }}" + echo "SemVer: ${{ steps.gitversion.outputs.semVer }}" + echo "LegacySemVer: ${{ steps.gitversion.outputs.legacySemVer }}" + echo "LegacySemVerPadded: ${{ steps.gitversion.outputs.legacySemVerPadded }}" + echo "AssemblySemVer: ${{ steps.gitversion.outputs.assemblySemVer }}" + echo "AssemblySemFileVer: ${{ steps.gitversion.outputs.assemblySemFileVer }}" + echo "FullSemVer: ${{ steps.gitversion.outputs.fullSemVer }}" + echo "InformationalVersion: ${{ steps.gitversion.outputs.informationalVersion }}" + echo "BranchName: ${{ steps.gitversion.outputs.branchName }}" + echo "Sha: ${{ steps.gitversion.outputs.sha }}" + echo "ShortSha: ${{ steps.gitversion.outputs.shortSha }}" + echo "NuGetVersionV2: ${{ steps.gitversion.outputs.nuGetVersionV2 }}" + echo "NuGetVersion: ${{ steps.gitversion.outputs.nuGetVersion }}" + echo "NuGetPreReleaseTagV2: ${{ steps.gitversion.outputs.nuGetPreReleaseTagV2 }}" + echo "NuGetPreReleaseTag: ${{ steps.gitversion.outputs.nuGetPreReleaseTag }}" + echo "VersionSourceSha: ${{ steps.gitversion.outputs.versionSourceSha }}" + echo "CommitsSinceVersionSource: ${{ steps.gitversion.outputs.commitsSinceVersionSource }}" + echo "CommitsSinceVersionSourcePadded: ${{ steps.gitversion.outputs.commitsSinceVersionSourcePadded }}" + echo "CommitDate: ${{ steps.gitversion.outputs.commitDate }}" - name: Build - shell: pwsh - run: | - $DebugPreference = "Continue" - ./build.ps1 "${{matrix.options.framework}}" + run: dotnet build -c Release -f "${{matrix.options.framework}}" /p:packageversion="${{ steps.gitversion.outputs.nuGetVersion }}" + + # - name: Build + # shell: pwsh + # run: | + # $DebugPreference = "Continue" + # ./build.ps1 "${{matrix.options.framework}}" - name: Test shell: pwsh diff --git a/gitversion.yml b/gitversion.yml new file mode 100644 index 0000000000..42dc350f95 --- /dev/null +++ b/gitversion.yml @@ -0,0 +1,6 @@ +continuous-delivery-fallback-tag: ci +branches: + master: + tag: dev + pull-request: + tag: pr From b3a71a7f9802a1a241174ec4f39929606e87a26a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 13:21:54 +1100 Subject: [PATCH 31/53] Update build-and-test.yml --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index ffee25a66c..db142c9e9f 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -35,7 +35,7 @@ jobs: runs-on: ${{ matrix.options.os }} steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Install nuget uses: NuGet/setup-nuget@v1 From 76f27ddd2f0133ff24aa3e11afebd96d68fcd49b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 13:30:30 +1100 Subject: [PATCH 32/53] Delete gitversion.yml --- gitversion.yml | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 gitversion.yml diff --git a/gitversion.yml b/gitversion.yml deleted file mode 100644 index 42dc350f95..0000000000 --- a/gitversion.yml +++ /dev/null @@ -1,6 +0,0 @@ -continuous-delivery-fallback-tag: ci -branches: - master: - tag: dev - pull-request: - tag: pr From 6a40693aedd95bd2fd7b72cf2d56fe81a38c62ab Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 13:33:21 +1100 Subject: [PATCH 33/53] Create GitVersion.yml --- GitVersion.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 GitVersion.yml diff --git a/GitVersion.yml b/GitVersion.yml new file mode 100644 index 0000000000..42dc350f95 --- /dev/null +++ b/GitVersion.yml @@ -0,0 +1,6 @@ +continuous-delivery-fallback-tag: ci +branches: + master: + tag: dev + pull-request: + tag: pr From afbc1cb29e6e30053028b8b67e57ce5dd8903800 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 16:51:48 +1100 Subject: [PATCH 34/53] Cleanup --- .github/workflows/build-and-test.yml | 80 +++----------- .travis.yml | 43 -------- CodeCoverage.runsettings | 22 ---- ImageSharp.sln | 12 +-- README.md | 13 +-- appveyor.yml | 67 ------------ build.ps1 | 150 --------------------------- ci-build.ps1 | 19 ++++ test.ps1 => ci-test.ps1 | 0 codecov.yml | 4 - tests/CodeCoverage/CodeCoverage.cmd | 21 ---- tests/CodeCoverage/CodeCoverage.ps1 | 11 -- tests/CodeCoverage/packages.config | 4 - 13 files changed, 43 insertions(+), 403 deletions(-) delete mode 100644 .travis.yml delete mode 100644 CodeCoverage.runsettings delete mode 100644 appveyor.yml delete mode 100644 build.ps1 create mode 100644 ci-build.ps1 rename test.ps1 => ci-test.ps1 (100%) delete mode 100644 codecov.yml delete mode 100644 tests/CodeCoverage/CodeCoverage.cmd delete mode 100644 tests/CodeCoverage/CodeCoverage.ps1 delete mode 100644 tests/CodeCoverage/packages.config diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index db142c9e9f..cf97ccdea0 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -32,12 +32,12 @@ jobs: # runtime: -x86 # codecov: false - runs-on: ${{ matrix.options.os }} + runs-on: ${{matrix.options.os}} steps: - uses: actions/checkout@v2 - - name: Install nuget + - name: Install NuGet uses: NuGet/setup-nuget@v1 - name: Setup Git @@ -47,7 +47,7 @@ jobs: git fetch --prune --unshallow git submodule -q update --init --recursive - - name: Fetch tags for GitVersion + - name: Fetch Tags for GitVersion run: | git fetch --tags @@ -63,50 +63,14 @@ jobs: - name: Use GitVersion id: gitversion # step id used as reference for output values uses: gittools/actions/execute-gitversion@v0.3 - - run: | - echo "Major: ${{ steps.gitversion.outputs.major }}" - echo "Minor: ${{ steps.gitversion.outputs.minor }}" - echo "Patch: ${{ steps.gitversion.outputs.patch }}" - echo "PreReleaseTag: ${{ steps.gitversion.outputs.preReleaseTag }}" - echo "PreReleaseTagWithDash: ${{ steps.gitversion.outputs.preReleaseTagWithDash }}" - echo "PreReleaseLabel: ${{ steps.gitversion.outputs.preReleaseLabel }}" - echo "PreReleaseNumber: ${{ steps.gitversion.outputs.preReleaseNumber }}" - echo "WeightedPreReleaseNumber: ${{ steps.gitversion.outputs.weightedPreReleaseNumber }}" - echo "BuildMetaData: ${{ steps.gitversion.outputs.buildMetaData }}" - echo "BuildMetaDataPadded: ${{ steps.gitversion.outputs.buildMetaDataPadded }}" - echo "FullBuildMetaData: ${{ steps.gitversion.outputs.fullBuildMetaData }}" - echo "MajorMinorPatch: ${{ steps.gitversion.outputs.majorMinorPatch }}" - echo "SemVer: ${{ steps.gitversion.outputs.semVer }}" - echo "LegacySemVer: ${{ steps.gitversion.outputs.legacySemVer }}" - echo "LegacySemVerPadded: ${{ steps.gitversion.outputs.legacySemVerPadded }}" - echo "AssemblySemVer: ${{ steps.gitversion.outputs.assemblySemVer }}" - echo "AssemblySemFileVer: ${{ steps.gitversion.outputs.assemblySemFileVer }}" - echo "FullSemVer: ${{ steps.gitversion.outputs.fullSemVer }}" - echo "InformationalVersion: ${{ steps.gitversion.outputs.informationalVersion }}" - echo "BranchName: ${{ steps.gitversion.outputs.branchName }}" - echo "Sha: ${{ steps.gitversion.outputs.sha }}" - echo "ShortSha: ${{ steps.gitversion.outputs.shortSha }}" - echo "NuGetVersionV2: ${{ steps.gitversion.outputs.nuGetVersionV2 }}" - echo "NuGetVersion: ${{ steps.gitversion.outputs.nuGetVersion }}" - echo "NuGetPreReleaseTagV2: ${{ steps.gitversion.outputs.nuGetPreReleaseTagV2 }}" - echo "NuGetPreReleaseTag: ${{ steps.gitversion.outputs.nuGetPreReleaseTag }}" - echo "VersionSourceSha: ${{ steps.gitversion.outputs.versionSourceSha }}" - echo "CommitsSinceVersionSource: ${{ steps.gitversion.outputs.commitsSinceVersionSource }}" - echo "CommitsSinceVersionSourcePadded: ${{ steps.gitversion.outputs.commitsSinceVersionSourcePadded }}" - echo "CommitDate: ${{ steps.gitversion.outputs.commitDate }}" - name: Build - run: dotnet build -c Release -f "${{matrix.options.framework}}" /p:packageversion="${{ steps.gitversion.outputs.nuGetVersion }}" - - # - name: Build - # shell: pwsh - # run: | - # $DebugPreference = "Continue" - # ./build.ps1 "${{matrix.options.framework}}" + shell: pwsh + run: ./ci-build.ps1 "${{steps.gitversion.outputs.nuGetVersion}}" "${{matrix.options.framework}}" - name: Test shell: pwsh - run: ./test.ps1 "${{ matrix.options.os }}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}" + run: ./ci-test.ps1 "${{matrix.options.os}}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}" env: XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit @@ -117,24 +81,14 @@ jobs: token: ${{secrets.CODECOV_TOKEN}} file: "coverage.${{matrix.options.framework}}.xml" flags: unittests - # Publish: - # runs-on: windows-latest - # needs: [Build] - # if: github.event_name == 'push' - # steps: - # - uses: actions/checkout@v1 - # - name: install nuget - # uses: NuGet/setup-nuget@v1 - # - name: Enable long file paths - # run: git config --global core.longpaths true - # - name: Update submodules - # run: git submodule -q update --init --recursive - # - name: Build - # shell: pwsh - # run: | - # $DebugPreference = "Continue" - # ./build.ps1 - # - name: Publish to nightly feed -myget - # if: success() - # run: nuget.exe push .\artifacts\*.nupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v2/package - # TODO: if github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org + + - name: Pack + if: matrix.options.codecov == true # We can use this filter as we know it happens only once and takes the most ime to complete. + shell: pwsh + run: ./ci-build.ps1 "${{steps.gitversion.outputs.nuGetVersion}}" + + - name: Publish to MyGet + if: (github.event_name == 'push') && (matrix.options.codecov == true) + shell: pwsh + run: nuget.exe push .\artifacts\*.nupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v2/package + # TODO: If github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 6fd38484dd..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,43 +0,0 @@ -language: csharp -solution: ImageSharp.sln - -matrix: - include: - - os: linux # Ubuntu 16.04 - dist: xenial - sudo: required - dotnet: 2.1.603 - mono: latest -# - os: osx # OSX 10.11 -# osx_image: xcode7.3.1 -# dotnet: 1.0.0-preview2-003121 -# mono: latest - -branches: - only: - - master - - coverity_scan - -script: - - git submodule -q update --init - - dotnet restore - - dotnet test tests/ImageSharp.Tests/ImageSharp.Tests.csproj -c Release -f "netcoreapp2.1" - -env: - global: - # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created - # via the "travis encrypt" command using the project repo's public key - - secure: "rjMvEMN9rpvIXqXqCAAKzbHyABzr7E4wPU/dYJ/mHBqlCccFpQrEXVVM1MfRFXYuWZSaIioknhLATZjT5xvIYpTNM6D57z4OTmqeRHhYm80=" - -before_install: - - echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- - -addons: - coverity_scan: - project: - name: "SixLabors/ImageSharp" - description: "Build submitted via Travis CI" - notification_email: james_south@hotmail.com - build_command_prepend: "dotnet restore" - build_command: "dotnet build -c Release" - branch_pattern: coverity_scan \ No newline at end of file diff --git a/CodeCoverage.runsettings b/CodeCoverage.runsettings deleted file mode 100644 index d9c0848f13..0000000000 --- a/CodeCoverage.runsettings +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - .*ImageSharp.dll - - - .*tests* - .*Tests* - - - - - - - - \ No newline at end of file diff --git a/ImageSharp.sln b/ImageSharp.sln index eb6c617d09..9c627791e9 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -3,24 +3,20 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.28902.138 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig .gitattributes = .gitattributes .gitignore = .gitignore .gitmodules = .gitmodules - .travis.yml = .travis.yml - appveyor.yml = appveyor.yml - build.cmd = build.cmd - build.ps1 = build.ps1 - codecov.yml = codecov.yml - CodeCoverage.runsettings = CodeCoverage.runsettings + ci-build.ps1 = ci-build.ps1 + ci-test.ps1 = ci-test.ps1 Directory.Build.props = Directory.Build.props Directory.Build.targets = Directory.Build.targets + GitVersion.yml = GitVersion.yml ImageSharp.sln.DotSettings = ImageSharp.sln.DotSettings LICENSE = LICENSE README.md = README.md - run-tests.ps1 = run-tests.ps1 EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{1799C43E-5C54-4A8F-8D64-B1475241DB0D}" diff --git a/README.md b/README.md index ba897fa7ef..c0bc345737 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ Install stable releases via Nuget; development releases are available via MyGet. | Package Name | Release (NuGet) | Nightly (MyGet) | |--------------------------------|-----------------|-----------------| | `SixLabors.ImageSharp` | [![NuGet](https://img.shields.io/nuget/v/SixLabors.ImageSharp.svg)](https://www.nuget.org/packages/SixLabors.ImageSharp/) | [![MyGet](https://img.shields.io/myget/sixlabors/v/SixLabors.ImageSharp.svg)](https://www.myget.org/feed/sixlabors/package/nuget/SixLabors.ImageSharp) | -| `SixLabors.ImageSharp.Drawing` | [![NuGet](https://img.shields.io/nuget/v/SixLabors.ImageSharp.Drawing.svg)](https://www.nuget.org/packages/SixLabors.ImageSharp.Drawing/) | [![MyGet](https://img.shields.io/myget/sixlabors/v/SixLabors.ImageSharp.Drawing.svg)](https://www.myget.org/feed/sixlabors/package/nuget/SixLabors.ImageSharp.Drawing) | ### Packages @@ -46,17 +45,11 @@ The **ImageSharp** library is made up of multiple packages: - Transform methods like Resize, Crop, Skew, Rotate - anything that alters the dimensions of the image - Non-transform methods like Gaussian Blur, Pixelate, Edge Detection - anything that maintains the original image dimensions -- **SixLabors.ImageSharp.Drawing** - - Brushes and various drawing algorithms, including drawing images - - Various vector drawing methods for drawing paths, polygons etc. - - Text drawing - ### Build Status -| |Build Status|Code Coverage| -|-------------|:----------:|:-----------:| -|**Linux/Mac**|[![Build Status](https://travis-ci.org/SixLabors/ImageSharp.svg)](https://travis-ci.org/SixLabors/ImageSharp)|[![Code coverage](https://codecov.io/gh/SixLabors/ImageSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/SixLabors/ImageSharp)| -|**Windows** |[![Build Status](https://ci.appveyor.com/api/projects/status/m9pn907xdah3ca39/branch/master?svg=true)](https://ci.appveyor.com/project/six-labors/imagesharp/branch/master)|[![Code coverage](https://codecov.io/gh/SixLabors/ImageSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/SixLabors/ImageSharp)| +|Build Status|Code Coverage| +|:----------:|:-----------:| +|[![Build Status](https://img.shields.io/github/workflow/status/SixLabors/ImageSharp/Build/master)](https://github.com/SixLabors/ImageSharp/actions)|[![Code coverage](https://codecov.io/gh/SixLabors/ImageSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/SixLabors/ImageSharp)| ### Questions? diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 87137da2f3..0000000000 --- a/appveyor.yml +++ /dev/null @@ -1,67 +0,0 @@ -version: 1.0.0.{build} -image: Visual Studio 2017 - -# prevent the double build when a branch has an active PR -skip_branch_with_pr: true - -environment: - matrix: - - target_framework: netcoreapp2.1 - is_32bit: False - - - target_framework: netcoreapp2.1 - is_32bit: True - - - target_framework: net472 - is_32bit: False - - - target_framework: net472 - is_32bit: True - - - target_framework: net462 - is_32bit: False - - - target_framework: net462 - is_32bit: True - - #- target_framework: mono - # is_32bit: False - #- target_framework: mono - # is_32bit: True - #- target_framework: net47 - # is_32bit: False - #- target_framework: net47 - # is_32bit: True - -install: - - ps: | - if ($env:target_framework -eq "mono") { - if ($env:is_32bit -eq "True") { - cinst mono --x86 - } else { - cinst mono - } - } - -before_build: - - git submodule -q update --init - - cmd: dotnet --info - -build_script: - - cmd: build.cmd - -test_script: - - ps: .\run-tests.ps1 $env:target_framework $env:is_32bit - -after_test: - - cmd: appveyor PushArtifact "artifacts\SixLabors.ImageSharp.%APPVEYOR_BUILD_VERSION%.nupkg" -# deploy: -# # MyGet Deployment for builds & releases -# - provider: NuGet -# server: https://www.myget.org/F/sixlabors/api/v2/package -# symbol_server: https://www.myget.org/F/sixlabors/symbols/api/v2/package -# api_key: -# secure: V/lEHP0UeMWIpWd0fiNlY2IgbCnJKQlGdRksECdJbOBdaE20Fl0RNL7WyqHe02o4 -# artifact: /.*\.nupkg/ -# on: -# branch: master diff --git a/build.ps1 b/build.ps1 deleted file mode 100644 index fd7ac61908..0000000000 --- a/build.ps1 +++ /dev/null @@ -1,150 +0,0 @@ -param( - [string]$targetFramework = 'ALL' -) - -# Lets calculate the correct version here -$fallbackVersion = "1.0.0"; -$version = '' - -$tagRegex = '^v?(\d+\.\d+\.\d+)(?:-([a-zA-Z]+)\.?(\d*))?$' - -function ToBuildNumber { - param( $date ) - - if ("$date" -eq "") { - $date = [System.DateTime]::Now - } - - if ($date.GetType().fullname -ne 'System.DateTime') { - $date = [System.DateTime]::Parse($date) - } - - return $date.ToString("yyyyMMddhhmmss") -} - -# We are running on the build server -$isVersionTag = "$env:GITHUB_REF".replace("refs/tags/", "") -match $tagRegex - -if ($isVersionTag) { - Write-Debug "Github tagged build" -} - -if ($isVersionTag -eq $false) { - if ( "$(git diff --stat)" -eq '') { - Write-Debug "Clean repo" - if ("$(git tag --list)" -ne "") { - Write-Debug "Has tags" - $tagData = (git describe --tags HEAD) - $isVersionTag = $tagData -match $tagRegex - Write-Debug $tagData - } - } - else { - Write-Debug "Dirty repo" - } -} - -if ($isVersionTag) { - - Write-Debug "Building commit tagged with a compatable version number" - - $version = $matches[1] - $postTag = $matches[2] - $count = $matches[3] - - Write-Debug "Version number: ${version} post tag: ${postTag} count: ${count}" - - if ("$postTag" -ne "") { - $version = "${version}-${postTag}" - } - - if ("$count" -ne "") { - # For consistancy with previous releases we pad the counter to only 4 places - $padded = $count.Trim().PadLeft(4, "0"); - Write-Debug "count '$count', padded '${padded}'" - - $version = "${version}${padded}" - } -} -else { - - Write-Debug "Untagged" - $lastTag = (git tag --list --sort=-taggerdate) | Out-String - $list = $lastTag.Split("`n") - foreach ($tag in $list) { - - Write-Debug "Testing ${tag}" - $tag = $tag.Trim(); - if ($tag -match $tagRegex) { - Write-Debug "Matched ${tag}" - $version = $matches[1]; - break; - } - } - - if ("$version" -eq "") { - $version = $fallbackVersion - Write-Debug "Failed to discover base version Fallback to '${version}'" - } - else { - - Write-Debug "Discovered base version from tags '${version}'" - } - - # Create a build number based on the current datetime. - $buildNumber = "" - - if ( "$env:GITHUB_SHA" -ne '') { - $buildNumber = ToBuildNumber (git show -s --format=%ci $env:GITHUB_SHA) - } - elseif ( "$(git diff --stat)" -eq '') { - $buildNumber = ToBuildNumber (git show -s --format=%ci HEAD) - } - else { - $buildNumber = ToBuildNumber - } - - $buildNumber = "$buildNumber".Trim().PadLeft(12, "0"); - - Write-Debug "Building a branch commit" - - # This is a general branch commit - $branch = ((git rev-parse --abbrev-ref HEAD) | Out-String).Trim() - - if ("$branch" -eq "") { - $branch = "unknown" - } - - $branch = $branch.Replace("/", "-").ToLower() - - if ($branch.ToLower() -eq "master" -or $branch.ToLower() -eq "head") { - $branch = "dev" - } - - $version = "${version}-${branch}${buildNumber}"; -} - -Write-Host "Building version '${version}'" - -if ($targetFramework -ne 'ALL') { - $targetFramework = "-f $targetFramework" -} - -# dotnet restore $targetFramework /p:packageversion=$version /p:DisableImplicitNuGetFallbackFolder=true - -$repositoryUrl = "" - -if ("$env:GITHUB_REPOSITORY" -ne "") { - $repositoryUrl = "https://github.com/$env:GITHUB_REPOSITORY" -} - -Write-Host "Building projects" - -dotnet build -c Release ${$targetFramework} /p:packageversion=$version /p:RepositoryUrl=$repositoryUrl - -if ($LASTEXITCODE ) { Exit $LASTEXITCODE } - -# Write-Host "Packaging projects" - -# dotnet pack -c Release --output "$PSScriptRoot/artifacts" --no-build /p:packageversion=$version /p:skipFullFramework=$skipFullFramework /p:RepositoryUrl=$repositoryUrl -# if ($LASTEXITCODE ) { Exit $LASTEXITCODE } diff --git a/ci-build.ps1 b/ci-build.ps1 new file mode 100644 index 0000000000..934b471d1e --- /dev/null +++ b/ci-build.ps1 @@ -0,0 +1,19 @@ +param( + [Parameter(Mandatory, Position = 0)] + [string]$version, + [string]$targetFramework = 'ALL' +) + +dotnet clean -c Release + +$repositoryUrl = "https://github.com/$env:GITHUB_REPOSITORY" +if ($targetFramework -ne 'ALL') { + + # Building for a specific framework. + dotnet build -c Release -f $targetFramework /p:packageversion=$version /p:RepositoryUrl=$repositoryUrl +} +else { + + # Building for packing and publishing. + dotnet pack -c Release --output "$PSScriptRoot/artifacts" /p:packageversion=$version /p:RepositoryUrl=$repositoryUrl +} diff --git a/test.ps1 b/ci-test.ps1 similarity index 100% rename from test.ps1 rename to ci-test.ps1 diff --git a/codecov.yml b/codecov.yml deleted file mode 100644 index ae6dd5f6bf..0000000000 --- a/codecov.yml +++ /dev/null @@ -1,4 +0,0 @@ -ignore: - "src/ImageSharp/Common/Helpers/DebugGuard.cs" - - \ No newline at end of file diff --git a/tests/CodeCoverage/CodeCoverage.cmd b/tests/CodeCoverage/CodeCoverage.cmd deleted file mode 100644 index 9b14c163c7..0000000000 --- a/tests/CodeCoverage/CodeCoverage.cmd +++ /dev/null @@ -1,21 +0,0 @@ -@echo off - - -cd tests\CodeCoverage - -nuget restore packages.config -PackagesDirectory . - -cd .. -cd .. - -dotnet restore ImageSharp.sln -rem Clean the solution to force a rebuild with /p:codecov=true -dotnet clean ImageSharp.sln -c Release -rem The -threshold options prevents this taking ages... -tests\CodeCoverage\OpenCover.4.7.922\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f netcoreapp2.1 /p:codecov=true" -register:user -threshold:10 -oldStyle -safemode:off -output:.\ImageSharp.Coverage.xml -hideskipped:All -returntargetcode -filter:"+[SixLabors.ImageSharp*]*" - -if %errorlevel% neq 0 exit /b %errorlevel% - -SET PATH=C:\\Python34;C:\\Python34\\Scripts;%PATH% -pip install codecov -codecov -f "ImageSharp.Coverage.xml" diff --git a/tests/CodeCoverage/CodeCoverage.ps1 b/tests/CodeCoverage/CodeCoverage.ps1 deleted file mode 100644 index b7073998f9..0000000000 --- a/tests/CodeCoverage/CodeCoverage.ps1 +++ /dev/null @@ -1,11 +0,0 @@ - -if((Test-Path("$PSScriptRoot\OpenCover.4.6.519")) -eq $false){ - Invoke-WebRequest https://www.nuget.org/api/v2/package/OpenCover/4.7.922 -OutFile "$PSScriptRoot\opencover.zip" - [IO.Compression.Zipfile]::ExtractToDirectory("$PSScriptRoot\opencover.zip","$PSScriptRoot\OpenCover.4.6.519") -} - -dotnet clean ImageSharp.sln -c Release - -& "$PSScriptRoot\OpenCover.4.6.519\tools\OpenCover.Console.exe" -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f netcoreapp2.1 /p:skipFullFramework=true /p:codecov=true" -register:user -threshold:10 -oldStyle -safemode:off -output:.\ImageSharp.Coverage.xml -hideskipped:All -returntargetcode -filter:"+[SixLabors.ImageSharp*]*" - -if ($LASTEXITCODE ){ Exit $LASTEXITCODE } \ No newline at end of file diff --git a/tests/CodeCoverage/packages.config b/tests/CodeCoverage/packages.config deleted file mode 100644 index 973b7f81b4..0000000000 --- a/tests/CodeCoverage/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file From c6f282c0264e5f8b38bc5d9a3dd35e0103db2c3e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 16:59:18 +1100 Subject: [PATCH 35/53] Update ci-build.ps1 --- ci-build.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/ci-build.ps1 b/ci-build.ps1 index 934b471d1e..ad757dc9e2 100644 --- a/ci-build.ps1 +++ b/ci-build.ps1 @@ -1,6 +1,7 @@ param( [Parameter(Mandatory, Position = 0)] [string]$version, + [Parameter(Mandatory = $false, Position = 1)] [string]$targetFramework = 'ALL' ) From a9576efa3615d902b1760ae8a7536a2879b0ae2d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 20:43:07 +1100 Subject: [PATCH 36/53] Cleanup solution --- .gitattributes | 6 + .github/workflows/build-and-test.yml | 4 +- Directory.Build.props | 10 +- Directory.Build.targets | 4 +- ImageSharp.sln | 1 - ImageSharp.sln.DotSettings | 393 ------------------ shared-infrastructure | 2 +- src/Directory.Build.props | 10 +- src/ImageSharp/ImageSharp.csproj | 1 - tests/Directory.Build.props | 8 +- tests/Directory.Build.targets | 1 - .../ImageSharp.Benchmarks.csproj | 2 +- .../ImageSharp.Sandbox46.csproj | 1 + .../ImageSharp.Tests/ImageSharp.Tests.csproj | 3 - .../ImageSharp.Tests.v3.ncrunchproject | 9 - tests/ImageSharp.Tests/RunExtendedTests.cmd | 9 - 16 files changed, 26 insertions(+), 438 deletions(-) delete mode 100644 ImageSharp.sln.DotSettings delete mode 100644 tests/ImageSharp.Tests/ImageSharp.Tests.v3.ncrunchproject delete mode 100644 tests/ImageSharp.Tests/RunExtendedTests.cmd diff --git a/.gitattributes b/.gitattributes index 0f550f4074..dd66250813 100644 --- a/.gitattributes +++ b/.gitattributes @@ -87,18 +87,24 @@ # Set explicit file behavior to: # treat as binary ############################################################################### +*.basis binary *.bmp binary +*.dds binary *.dll binary *.eot binary *.exe binary *.gif binary *.jpg binary +*.ktx binary +*.pbm binary *.pdf binary *.png binary *.ppt binary *.pptx binary +*.pvr binary *.ttf binary *.snk binary +*.tga binary *.ttf binary *.woff binary *.woff2 binary diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index cf97ccdea0..0cc3f96443 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -82,8 +82,8 @@ jobs: file: "coverage.${{matrix.options.framework}}.xml" flags: unittests - - name: Pack - if: matrix.options.codecov == true # We can use this filter as we know it happens only once and takes the most ime to complete. + - name: Pack # We can use this filter as we know it happens only once and takes the most time to complete. + if: (github.event_name == 'push') && (matrix.options.codecov == true) shell: pwsh run: ./ci-build.ps1 "${{steps.gitversion.outputs.nuGetVersion}}" diff --git a/Directory.Build.props b/Directory.Build.props index f961ae881e..dcdc62a52a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -79,10 +79,10 @@ Copyright © Six Labors and Contributors strict;IOperation true - 7.3 + 8.0 en true - https://raw.githubusercontent.com/SixLabors/Branding/master/icons/imagesharp/sixlabors.imagesharp.128.png + icon.png Apache-2.0 $(RepositoryUrl) true @@ -96,10 +96,14 @@ true - + + + + + diff --git a/Directory.Build.targets b/Directory.Build.targets index 1d158eccef..f69a873acc 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -20,13 +20,13 @@ - + + - diff --git a/ImageSharp.sln b/ImageSharp.sln index 9c627791e9..2adc18f46d 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -14,7 +14,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Directory.Build.props = Directory.Build.props Directory.Build.targets = Directory.Build.targets GitVersion.yml = GitVersion.yml - ImageSharp.sln.DotSettings = ImageSharp.sln.DotSettings LICENSE = LICENSE README.md = README.md EndProjectSection diff --git a/ImageSharp.sln.DotSettings b/ImageSharp.sln.DotSettings deleted file mode 100644 index ece3dddb3c..0000000000 --- a/ImageSharp.sln.DotSettings +++ /dev/null @@ -1,393 +0,0 @@ - - <?xml version="1.0" encoding="utf-16"?> -<Profile name="StyleCop"> - <CSUpdateFileHeader>False</CSUpdateFileHeader> - <CSArrangeQualifiers>True</CSArrangeQualifiers> - <CSOptimizeUsings> - <OptimizeUsings>True</OptimizeUsings> - <EmbraceInRegion>False</EmbraceInRegion> - <RegionName></RegionName> - </CSOptimizeUsings> - <CSReformatCode>True</CSReformatCode> - <CSReorderTypeMembers>True</CSReorderTypeMembers> -</Profile> - StyleCop - public protected internal private static new abstract virtual override sealed readonly extern unsafe volatile async - Field, Property, Event, Method - True - True - True - True - True - True - True - True - True - NEXT_LINE_SHIFTED_2 - 1 - 1 - 1 - 1 - 1 - NEXT_LINE_SHIFTED_2 - ALWAYS_ADD - ALWAYS_ADD - ALWAYS_ADD - ALWAYS_ADD - ALWAYS_ADD - NEXT_LINE_SHIFTED_2 - 1 - 1 - False - False - False - NEVER - False - False - NEVER - False - ALWAYS - False - True - ON_SINGLE_LINE - False - True - True - False - True - True - CHOP_IF_LONG - True - True - CHOP_IF_LONG - CHOP_IF_LONG - <?xml version="1.0" encoding="utf-16"?> -<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> - <TypePattern DisplayName="COM interfaces or structs"> - <TypePattern.Match> - <Or> - <And> - <Kind Is="Interface" /> - <Or> - <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /> - <HasAttribute Name="System.Runtime.InteropServices.ComImport" /> - </Or> - </And> - <Kind Is="Struct" /> - </Or> - </TypePattern.Match> - </TypePattern> - <TypePattern DisplayName="P/Invoke classes called 'NativeMethods' (StyleCop)"> - <TypePattern.Match> - <And> - <Kind Is="Class" /> - <Name Is=".*NativeMethods" /> - </And> - </TypePattern.Match> - </TypePattern> - <TypePattern DisplayName="DataMember serialisation classes (StyleCop)"> - <TypePattern.Match> - <And> - <Or> - <Kind Is="Field" /> - <Kind Is="Property" /> - </Or> - <HasAttribute Name="System.Runtime.Serialization.DataMemberAttribute" /> - </And> - </TypePattern.Match> - </TypePattern> - <TypePattern DisplayName="Default Pattern (StyleCop)" RemoveRegions="All"> - <Entry DisplayName="Constants"> - <Entry.Match> - <Kind Is="Constant" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected Private" /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Static fields"> - <Entry.Match> - <And> - <Kind Is="Field" /> - <Static /> - </And> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected Private" /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Fields"> - <Entry.Match> - <Kind Is="Field" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected Private" /> - <Readonly /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry Priority="200" DisplayName="Constructors and Destructors"> - <Entry.Match> - <Or> - <Kind Is="Constructor" /> - <Kind Is="Destructor" /> - </Or> - </Entry.Match> - <Entry.SortBy> - <Static /> - <Kind Order="Constructor Destructor" /> - <Access Order="Public Internal ProtectedInternal Protected Private" /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Delegates"> - <Entry.Match> - <Kind Is="Delegate" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected Private" /> - <Static /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Public events"> - <Entry.Match> - <And> - <Kind Is="Event" /> - <Access Is="Public" /> - </And> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public" /> - <Static /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Interface events"> - <Entry.Match> - <And> - <Kind Is="Event" /> - <ImplementsInterface /> - </And> - </Entry.Match> - <Entry.SortBy> - <ImplementsInterface Immediate="True" /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Other events"> - <Entry.Match> - <Kind Is="Event" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected Private" /> - <Static /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Enums"> - <Entry.Match> - <Kind Is="Enum" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected Private" /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Interfaces"> - <Entry.Match> - <Kind Is="Interface" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected Private" /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Public properties"> - <Entry.Match> - <And> - <Kind Is="Property" /> - <Access Is="Public" /> - </And> - </Entry.Match> - <Entry.SortBy> - <Static /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Interface properties"> - <Entry.Match> - <And> - <Kind Is="Property" /> - <ImplementsInterface /> - </And> - </Entry.Match> - <Entry.SortBy> - <ImplementsInterface Immediate="True" /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Other properties"> - <Entry.Match> - <Kind Is="Property" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected Private" /> - <Static /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry Priority="1000" DisplayName="Public indexers"> - <Entry.Match> - <And> - <Kind Is="Indexer" /> - <Access Is="Public" /> - </And> - </Entry.Match> - <Entry.SortBy> - <Static /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry Priority="1000" DisplayName="Interface indexers"> - <Entry.Match> - <And> - <Kind Is="Indexer" /> - <ImplementsInterface /> - </And> - </Entry.Match> - <Entry.SortBy> - <ImplementsInterface Immediate="True" /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry Priority="1000" DisplayName="Other indexers"> - <Entry.Match> - <Kind Is="Indexer" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected Private" /> - <Static /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Public methods and operators"> - <Entry.Match> - <And> - <Or> - <Kind Is="Method" /> - <Kind Is="Operator" /> - </Or> - <Access Is="Public" /> - </And> - </Entry.Match> - <Entry.SortBy> - <Static /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Interface methods"> - <Entry.Match> - <And> - <Kind Is="Method" /> - <ImplementsInterface /> - </And> - </Entry.Match> - <Entry.SortBy> - <ImplementsInterface Immediate="True" /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Other methods"> - <Entry.Match> - <Kind Is="Method" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected Private" /> - <Static /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="Operators"> - <Entry.Match> - <Kind Is="Operator" /> - </Entry.Match> - <Entry.SortBy> - <Access Order="Public Internal ProtectedInternal Protected Private" /> - <Static /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry Priority="600" DisplayName="Nested structs"> - <Entry.Match> - <Kind Is="Struct" /> - </Entry.Match> - <Entry.SortBy> - <Static /> - <Access Order="Public Internal ProtectedInternal Protected Private" /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry Priority="700" DisplayName="Nested classes"> - <Entry.Match> - <Kind Is="Class" /> - </Entry.Match> - <Entry.SortBy> - <Static /> - <Access Order="Public Internal ProtectedInternal Protected Private" /> - <Name /> - </Entry.SortBy> - </Entry> - <Entry DisplayName="All other members" /> - </TypePattern> -</Patterns> - False - True - // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - - AC - DC - DCT - EOF - FDCT - IDCT - JPEG - MCU - PNG - RGB - RLE - XY - XYZ - $object$_On$event$ - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - True - True - True - True - True - True - True - True - True - True - True - True - \ No newline at end of file diff --git a/shared-infrastructure b/shared-infrastructure index c2e689abe9..40f740dea2 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit c2e689abe9227209e6d5bc4bf56255d92b4a5d62 +Subproject commit 40f740dea2aad9dabae12a8e1e17fdcf476066ba diff --git a/src/Directory.Build.props b/src/Directory.Build.props index e94848675f..0bddf7e696 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -25,11 +25,7 @@ true - - - - - + @@ -38,8 +34,4 @@ - - - - diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 4d354d3cca..5e64adf537 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -192,7 +192,6 @@ - diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 48ffbf315a..22c634d9b2 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -17,7 +17,9 @@ - CS0618;$(NoWarn) + $(MSBuildThisFileDirectory)..\shared-infrastructure\SixLabors.Tests.ruleset + + $(NoWarn);CS0618 @@ -26,8 +28,8 @@ - + + diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets index 5c8f45e26b..40347763d9 100644 --- a/tests/Directory.Build.targets +++ b/tests/Directory.Build.targets @@ -26,7 +26,6 @@ - full true true opencover diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index bac4ad71c3..70c5481dac 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -7,7 +7,7 @@ SixLabors.ImageSharp.Benchmarks netcoreapp2.1;net472 false - false + diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index 289d2d8508..7afe33fb5c 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -10,6 +10,7 @@ win7-x64 netcoreapp2.1;net472 SixLabors.ImageSharp.Sandbox46.Program + false diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index d09ab9d0b3..743c2eee02 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -4,7 +4,6 @@ netcoreapp2.1;net462;net472 True - latest True SixLabors.ImageSharp.Tests AnyCPU;x64;x86 @@ -16,8 +15,6 @@ - - diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.v3.ncrunchproject b/tests/ImageSharp.Tests/ImageSharp.Tests.v3.ncrunchproject deleted file mode 100644 index f015b4b86e..0000000000 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.v3.ncrunchproject +++ /dev/null @@ -1,9 +0,0 @@ - - - False - UseStaticAnalysis - - False - False - - \ No newline at end of file diff --git a/tests/ImageSharp.Tests/RunExtendedTests.cmd b/tests/ImageSharp.Tests/RunExtendedTests.cmd deleted file mode 100644 index c2f4b9f537..0000000000 --- a/tests/ImageSharp.Tests/RunExtendedTests.cmd +++ /dev/null @@ -1,9 +0,0 @@ -dotnet build -c Release -dotnet xunit -nobuild -c Release -f net462 -dotnet xunit -nobuild -c Release -f net462 -x86 -dotnet xunit -nobuild -c Release -f net47 -dotnet xunit -nobuild -c Release -f net47 -x86 -dotnet xunit -nobuild -c Release -f net471 -dotnet xunit -nobuild -c Release -f net471 -x86 -dotnet xunit -nobuild -c Release -f net472 -dotnet xunit -nobuild -c Release -f net472 -x86 From 9dc422d8a1dbc047e13f2d044938a8203b608dd7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 21:29:22 +1100 Subject: [PATCH 37/53] Add new target frameworks --- .github/workflows/build-and-test.yml | 8 ++++-- Directory.Build.props | 27 +++++++++---------- src/ImageSharp/Common/Helpers/TestHelpers.cs | 14 ++++++---- src/ImageSharp/ImageSharp.csproj | 2 +- tests/ImageSharp.Benchmarks/Config.cs | 1 + .../ImageSharp.Benchmarks.csproj | 2 +- .../ImageSharp.Sandbox46.csproj | 2 +- .../Image/ImageTests.WrapMemory.cs | 2 +- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 2 +- .../Tests/TestEnvironmentTests.cs | 23 ---------------- 10 files changed, 34 insertions(+), 49 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 0cc3f96443..2fc6f0b381 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -16,14 +16,18 @@ jobs: matrix: options: - os: ubuntu-latest - framework: netcoreapp2.1 + framework: netcoreapp3.1 runtime: -x64 codecov: false # - os: windows-latest - # framework: netcoreapp2.1 + # framework: netcoreapp3.1 # runtime: -x64 # codecov: true # - os: windows-latest + # framework: netcoreapp2.1 + # runtime: -x64 + # codecov: false + # - os: windows-latest # framework: net472 # runtime: -x64 # codecov: false diff --git a/Directory.Build.props b/Directory.Build.props index dcdc62a52a..02f7b77211 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -31,22 +31,21 @@ - - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING + $(DefineConstants);MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_RUNTIME_INTRINSICS; $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING @@ -55,7 +54,7 @@ $(DefineConstants);SUPPORTS_MATHF; - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING + $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING $(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS diff --git a/src/ImageSharp/Common/Helpers/TestHelpers.cs b/src/ImageSharp/Common/Helpers/TestHelpers.cs index d330233c4c..c6574e4b58 100644 --- a/src/ImageSharp/Common/Helpers/TestHelpers.cs +++ b/src/ImageSharp/Common/Helpers/TestHelpers.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. namespace SixLabors.ImageSharp.Common.Helpers @@ -13,14 +13,18 @@ namespace SixLabors.ImageSharp.Common.Helpers /// Only intended to be used in tests! /// internal const string ImageSharpBuiltAgainst = -#if NET472 - "netfx4.7.2"; +#if NETCOREAPP3_1 + "netcoreapp3.1"; #elif NETCOREAPP2_1 "netcoreapp2.1"; +#elif NETSTANDARD2_1 + "netstandard2.1"; +#elif NETSTANDARD2_0 + "netstandard2.0"; #elif NETSTANDARD1_3 "netstandard1.3"; #else - "netstandard2.0"; + "net472"; #endif } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 5e64adf537..f13989acdc 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -10,7 +10,7 @@ $(packageversion) 0.0.1 - netcoreapp2.1;netstandard2.0;netstandard1.3;net472 + netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472 true true diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs index 018a2e02bf..cb4fcbba18 100644 --- a/tests/ImageSharp.Benchmarks/Config.cs +++ b/tests/ImageSharp.Benchmarks/Config.cs @@ -21,6 +21,7 @@ namespace SixLabors.ImageSharp.Benchmarks { this.Add( Job.Default.With(ClrRuntime.Net472).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3), + Job.Default.With(CoreRuntime.Core31).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3), Job.Default.With(CoreRuntime.Core21).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3) ); } diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 70c5481dac..34f517500c 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -5,7 +5,7 @@ ImageSharp.Benchmarks Exe SixLabors.ImageSharp.Benchmarks - netcoreapp2.1;net472 + netcoreapp3.1;netcoreapp2.1;net472 false diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index 7afe33fb5c..e89b28dc11 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -8,7 +8,7 @@ false SixLabors.ImageSharp.Sandbox46 win7-x64 - netcoreapp2.1;net472 + netcoreapp3.1;netcoreapp2.1;net472 SixLabors.ImageSharp.Sandbox46.Program false diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index 63c2e57c8c..04d05f6dc7 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.Tests } private static bool ShouldSkipBitmapTest => - !TestEnvironment.Is64BitProcess || TestHelpers.ImageSharpBuiltAgainst != "netcoreapp2.1"; + !TestEnvironment.Is64BitProcess || (TestHelpers.ImageSharpBuiltAgainst != "netcoreapp3.1" && TestHelpers.ImageSharpBuiltAgainst != "netcoreapp2.1"); } } } diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 743c2eee02..41e6749be6 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -2,7 +2,7 @@ - netcoreapp2.1;net462;net472 + netcoreapp3.1;netcoreapp2.1;net472 True True SixLabors.ImageSharp.Tests diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs index 567a1b0302..07523f6178 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs @@ -33,29 +33,6 @@ namespace SixLabors.ImageSharp.Tests Assert.True(Directory.Exists(path)); } - ///// - ///// We need this test to make sure that the netcoreapp2.1 test execution actually covers the netcoreapp2.1 build configuration of ImageSharp. - ///// - //[Fact] - //public void ImageSharpAssemblyUnderTest_MatchesExpectedTargetFramework() - //{ - // this.Output.WriteLine("NetCoreVersion: " + TestEnvironment.NetCoreVersion); - // this.Output.WriteLine("ImageSharpBuiltAgainst: " + TestHelpers.ImageSharpBuiltAgainst); - - // if (string.IsNullOrEmpty(TestEnvironment.NetCoreVersion)) - // { - // this.Output.WriteLine("Not running under .NET Core!"); - // } - // else if (TestEnvironment.NetCoreVersion.StartsWith("2.1")) - // { - // Assert.Equal("netcoreapp2.1", TestHelpers.ImageSharpBuiltAgainst); - // } - // else - // { - // Assert.Equal("netstandard2.0", TestHelpers.ImageSharpBuiltAgainst); - // } - //} - [Fact] public void SolutionDirectoryFullPath() { From c957caa47b66407944169eced6d42c55d8e02810 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 21:37:09 +1100 Subject: [PATCH 38/53] Add netcore 3.1 SDK action --- .github/workflows/build-and-test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2fc6f0b381..74b3ea756b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -68,6 +68,11 @@ jobs: id: gitversion # step id used as reference for output values uses: gittools/actions/execute-gitversion@v0.3 + - name: Install DotNet SDK + - uses: actions/setup-dotnet@v1 + with: + dotnet-version: "3.1.101" # SDK Version to use. + - name: Build shell: pwsh run: ./ci-build.ps1 "${{steps.gitversion.outputs.nuGetVersion}}" "${{matrix.options.framework}}" From ec847dec4f7346561a710e0eaad8961b64837c5c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 21:41:00 +1100 Subject: [PATCH 39/53] Revert "Add netcore 3.1 SDK action" This reverts commit c957caa47b66407944169eced6d42c55d8e02810. --- .github/workflows/build-and-test.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 74b3ea756b..2fc6f0b381 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -68,11 +68,6 @@ jobs: id: gitversion # step id used as reference for output values uses: gittools/actions/execute-gitversion@v0.3 - - name: Install DotNet SDK - - uses: actions/setup-dotnet@v1 - with: - dotnet-version: "3.1.101" # SDK Version to use. - - name: Build shell: pwsh run: ./ci-build.ps1 "${{steps.gitversion.outputs.nuGetVersion}}" "${{matrix.options.framework}}" From ce124acf8c28e55ac5c0c443d43ff172a2a02fd1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 21:44:39 +1100 Subject: [PATCH 40/53] Add 3.1.101 SDK --- .github/workflows/build-and-test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2fc6f0b381..aac90f403e 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -68,6 +68,11 @@ jobs: id: gitversion # step id used as reference for output values uses: gittools/actions/execute-gitversion@v0.3 + - name: Setup DotNet SDK + uses: actions/setup-dotnet@v1 + with: + dotnet-version: "3.1.101" + - name: Build shell: pwsh run: ./ci-build.ps1 "${{steps.gitversion.outputs.nuGetVersion}}" "${{matrix.options.framework}}" From d7338e8829f4d04b46728276e33543ae8cf9c8dc Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 21:49:10 +1100 Subject: [PATCH 41/53] Update Directory.Build.props --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 02f7b77211..e4e52ac164 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -45,7 +45,7 @@ --> - $(DefineConstants);MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_RUNTIME_INTRINSICS; + $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_RUNTIME_INTRINSICS; $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING From 99434bf6622e54009665a0b27bfef71faca9aa18 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 21:54:50 +1100 Subject: [PATCH 42/53] Test xunit pipeline --- .github/workflows/build-and-test.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index aac90f403e..3a3cd65d16 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -15,10 +15,10 @@ jobs: strategy: matrix: options: - - os: ubuntu-latest - framework: netcoreapp3.1 - runtime: -x64 - codecov: false + # - os: ubuntu-latest + # framework: netcoreapp3.1 + # runtime: -x64 + # codecov: false # - os: windows-latest # framework: netcoreapp3.1 # runtime: -x64 @@ -27,10 +27,10 @@ jobs: # framework: netcoreapp2.1 # runtime: -x64 # codecov: false - # - os: windows-latest - # framework: net472 - # runtime: -x64 - # codecov: false + - os: windows-latest + framework: net472 + runtime: -x64 + codecov: false # - os: windows-latest # framework: net472 # runtime: -x86 From 5021507fe088a10c12bebaa5bcf51754f1d4c686 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 22:02:27 +1100 Subject: [PATCH 43/53] Move nuget fix --- .github/workflows/build-and-test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 3a3cd65d16..dc23f2560d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -41,9 +41,6 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Install NuGet - uses: NuGet/setup-nuget@v1 - - name: Setup Git run: | git config --global core.autocrlf false @@ -68,6 +65,9 @@ jobs: id: gitversion # step id used as reference for output values uses: gittools/actions/execute-gitversion@v0.3 + - name: Install NuGet + uses: NuGet/setup-nuget@v1 + - name: Setup DotNet SDK uses: actions/setup-dotnet@v1 with: From 0e0ed60fe31def023f0b033cedc90369a3272d92 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 22:06:20 +1100 Subject: [PATCH 44/53] Enable linux --- .github/workflows/build-and-test.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index dc23f2560d..75e0d664d7 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -15,10 +15,10 @@ jobs: strategy: matrix: options: - # - os: ubuntu-latest - # framework: netcoreapp3.1 - # runtime: -x64 - # codecov: false + - os: ubuntu-latest + framework: netcoreapp3.1 + runtime: -x64 + codecov: false # - os: windows-latest # framework: netcoreapp3.1 # runtime: -x64 @@ -41,6 +41,9 @@ jobs: steps: - uses: actions/checkout@v2 + - name: Install NuGet + uses: NuGet/setup-nuget@v1 + - name: Setup Git run: | git config --global core.autocrlf false @@ -65,9 +68,6 @@ jobs: id: gitversion # step id used as reference for output values uses: gittools/actions/execute-gitversion@v0.3 - - name: Install NuGet - uses: NuGet/setup-nuget@v1 - - name: Setup DotNet SDK uses: actions/setup-dotnet@v1 with: From c41a4c417bc09fd9b81b676e627cc068b187a161 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 22:31:43 +1100 Subject: [PATCH 45/53] Try using bash --- .github/workflows/build-and-test.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 75e0d664d7..1ca95c1e7a 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -15,10 +15,10 @@ jobs: strategy: matrix: options: - - os: ubuntu-latest - framework: netcoreapp3.1 - runtime: -x64 - codecov: false + # - os: ubuntu-latest + # framework: netcoreapp3.1 + # runtime: -x64 + # codecov: false # - os: windows-latest # framework: netcoreapp3.1 # runtime: -x64 @@ -45,6 +45,7 @@ jobs: uses: NuGet/setup-nuget@v1 - name: Setup Git + shell: bash run: | git config --global core.autocrlf false git config --global core.longpaths true From a639460daa3c2d09c661e9ac6ed9abfe7edeea13 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 22:43:21 +1100 Subject: [PATCH 46/53] Test all frameworks --- .github/workflows/build-and-test.yml | 32 ++++++++++++++-------------- README.md | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 1ca95c1e7a..e7f4a143b4 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -15,26 +15,26 @@ jobs: strategy: matrix: options: - # - os: ubuntu-latest - # framework: netcoreapp3.1 - # runtime: -x64 - # codecov: false - # - os: windows-latest - # framework: netcoreapp3.1 - # runtime: -x64 - # codecov: true - # - os: windows-latest - # framework: netcoreapp2.1 - # runtime: -x64 - # codecov: false + - os: ubuntu-latest + framework: netcoreapp3.1 + runtime: -x64 + codecov: false + - os: windows-latest + framework: netcoreapp3.1 + runtime: -x64 + codecov: true + - os: windows-latest + framework: netcoreapp2.1 + runtime: -x64 + codecov: false - os: windows-latest framework: net472 runtime: -x64 codecov: false - # - os: windows-latest - # framework: net472 - # runtime: -x86 - # codecov: false + - os: windows-latest + framework: net472 + runtime: -x86 + codecov: false runs-on: ${{matrix.options.os}} diff --git a/README.md b/README.md index c0bc345737..ceb1e51d22 100644 --- a/README.md +++ b/README.md @@ -106,9 +106,9 @@ For more examples check out: If you prefer, you can compile ImageSharp yourself (please do and help!) -- Using [Visual Studio 2017](https://visualstudio.microsoft.com/vs/) +- Using [Visual Studio 2019](https://visualstudio.microsoft.com/vs/) - Make sure you have the latest version installed - - Make sure you have [the .NET Core 2.1 SDK](https://www.microsoft.com/net/core#windows) installed + - Make sure you have [the .NET Core 3.1 SDK](https://www.microsoft.com/net/core#windows) installed Alternatively, you can work from command line and/or with a lightweight editor on **both Linux/Unix and Windows**: From a8425dd110d102e61327df36a2c347ce97840e28 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 23:15:59 +1100 Subject: [PATCH 47/53] Only use the xunit runner when we really have to. --- ci-test.ps1 | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/ci-test.ps1 b/ci-test.ps1 index c45074329f..fe470a04be 100644 --- a/ci-test.ps1 +++ b/ci-test.ps1 @@ -9,6 +9,8 @@ param( [string]$codecov ) + $netFxRegex = '^net\d+' + if ($codecov -eq 'true') { # xunit doesn't understand custom params so use dotnet test. @@ -17,29 +19,19 @@ if ($codecov -eq 'true') { dotnet clean -c Debug dotnet test -c Debug -f $targetFramework /p:codecov=true } -elseif ($os -ne 'windows-latest') { - # xunit doesn't run without mono on linux and macos. - dotnet test --no-build -c Release -f $targetFramework -} -else { - - # xunit has issues matching the correct installed runtime if we do not specify it explicitly. - # https://github.com/xunit/xunit/issues/1476 - # This fix assumes the base version is installed. - $coreTargetFrameworkRegex = '^netcoreapp(\d+\.\d+)$' - if ($targetFramework -match $coreTargetFrameworkRegex) { - $fxVersion = "--fx-version ${matches[1]}.0" - } +elseif ($platform -eq '-x86' -and $targetFramework -match $netFxRegex) { + # xunit doesn't run on core with NET SDK 3.1+. + # xunit doesn't actually understand -x64 as an option. + # # xunit requires explicit path. Set-Location $env:XUNIT_PATH - # xunit doesn't actually understand -x64 as an option. - if ($platform -ne '-x86') { - $platform = '' - } - dotnet xunit --no-build -c Release -f $targetFramework ${fxVersion} $platform Set-Location $PSScriptRoot } +else { + + dotnet test --no-build -c Release -f $targetFramework +} From 5f06fb9d9c38a868a688e10645bb8c2a0c47dba0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2020 23:42:22 +1100 Subject: [PATCH 48/53] Restore CI variable and skip troublesome tests --- .github/workflows/build-and-test.yml | 1 + tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index e7f4a143b4..4cb40d36a0 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -82,6 +82,7 @@ jobs: shell: pwsh run: ./ci-test.ps1 "${{matrix.options.os}}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}" env: + CI : True XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit - name: Update Codecov diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 41576cc0df..6aaa0c80ce 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -181,6 +181,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void WorksWithAllBitDepths(TestImageProvider provider, PngColorType pngColorType, PngBitDepth pngBitDepth) where TPixel : struct, IPixel { + // TODO: Investigate WuQuantizer to see if we can reduce memory pressure. + if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess) + { + return; + } + foreach (PngInterlaceMode interlaceMode in InterlaceMode) { TestPngEncoderCore( @@ -201,7 +207,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png where TPixel : struct, IPixel { // TODO: Investigate WuQuantizer to see if we can reduce memory pressure. - if (!TestEnvironment.Is64BitProcess) + if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess) { return; } From 45bc1bcb5e8d76fc1a22a7a31d3de9419ebed872 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 17 Jan 2020 00:40:31 +1100 Subject: [PATCH 49/53] Delete bak file and undo bad gitignore changes --- .github/workflows/build-and-test.yml.bak | 116 ----------------------- .gitignore | 4 +- 2 files changed, 1 insertion(+), 119 deletions(-) delete mode 100644 .github/workflows/build-and-test.yml.bak diff --git a/.github/workflows/build-and-test.yml.bak b/.github/workflows/build-and-test.yml.bak deleted file mode 100644 index 7d7d2ad26b..0000000000 --- a/.github/workflows/build-and-test.yml.bak +++ /dev/null @@ -1,116 +0,0 @@ -name: Build - -on: - push: - branches: - - master - tags: - - "v*" - pull_request: - branches: - - master - -jobs: - Coverage: - runs-on: windows-latest - needs: [Build] - steps: - - uses: actions/checkout@v1 - - - name: Install nuget - uses: NuGet/setup-nuget@v1 - - - name: Enable long file paths - run: git config --global core.longpaths true - - - name: Update submodules - run: git submodule -q update --init --recursive - - - name: Generate Test Coverage - shell: pwsh - run: ./tests/CodeCoverage/CodeCoverage.ps1 - env: - CI: True - - - name: Update codecov - uses: iansu/codecov-action-node@v1.0.0 - with: - token: ${{secrets.CODECOV_TOKEN}} - file: "ImageSharp.Coverage.xml" - flags: unittests - - Build: - strategy: - matrix: - opts: - - os: ubuntu-latest - framework: netcoreapp2.1 - is32Bit: False - doCoverage: False - - os: windows-latest - framework: netcoreapp2.1 - is32Bit: False - doCoverage: True - - os: windows-latest - framework: net472 - is32Bit: False - doCoverage: False - - os: windows-latest - framework: net472 - is32Bit: True - doCoverage: False - - runs-on: ${{ matrix.opts.os }} - - steps: - - uses: actions/checkout@v1 - - - name: install nuget - uses: NuGet/setup-nuget@v1 - - - name: Enable long file paths - run: | - git config --global core.autocrlf false - git config --global core.longpaths true - - - name: Update submodules - run: git submodule -q update --init - - - name: Build - shell: pwsh - run: | - $DebugPreference = "Continue" - ./build.ps1 "${{matrix.opts.framework}}" - - - name: Test - shell: pwsh - run: ./run-tests.ps1 "${{ matrix.opts.os }}" "${{matrix.opts.framework}}" "${{matrix.opts.is32Bit}}" "${{matrix.opts.doCoverage}}" - env: - CI: True - - Publish: - runs-on: windows-latest - needs: [Build] - if: github.event_name == 'push' - steps: - - uses: actions/checkout@v1 - - - name: install nuget - uses: NuGet/setup-nuget@v1 - - - name: Enable long file paths - run: git config --global core.longpaths true - - - name: Update submodules - run: git submodule -q update --init --recursive - - - name: Build - shell: pwsh - run: | - $DebugPreference = "Continue" - ./build.ps1 - - - name: Publish to nightly feed -myget - if: success() - run: nuget.exe push .\artifacts\*.nupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v2/package - # TODO: if github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org diff --git a/.gitignore b/.gitignore index 4007b1faba..8fcb5ef405 100644 --- a/.gitignore +++ b/.gitignore @@ -137,7 +137,7 @@ publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings +# TODO: Comment the next line if you want to checkin your web deploy settings # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj @@ -221,5 +221,3 @@ artifacts/ # Tests **/Images/ActualOutput **/Images/ReferenceOutput -/tests/CodeCoverage/opencover.zip -/tests/CodeCoverage/OpenCover.4.6.519 From 21ad572ee65e8d46a29ef2e25ddca87c096b626f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 17 Jan 2020 11:37:15 +1100 Subject: [PATCH 50/53] Speed up coverage and respond to comments --- ci-test.ps1 | 16 ++++++++-------- src/ImageSharp/Advanced/AotCompilerTools.cs | 2 ++ tests/Directory.Build.targets | 6 +++--- .../ImageSharp.Benchmarks.csproj | 1 + 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/ci-test.ps1 b/ci-test.ps1 index fe470a04be..c9cfc07a37 100644 --- a/ci-test.ps1 +++ b/ci-test.ps1 @@ -6,18 +6,18 @@ param( [Parameter(Mandatory, Position = 2)] [string]$platform, [Parameter(Mandatory, Position = 3)] - [string]$codecov + [string]$codecov, + [Parameter(Position = 4)] + [string]$codecovProfile = 'Release' ) - $netFxRegex = '^net\d+' +$netFxRegex = '^net\d+' if ($codecov -eq 'true') { - # xunit doesn't understand custom params so use dotnet test. - # Coverage tests are run in debug because the coverage tools are triggering a JIT error in filter processors - # that causes the blue component of transformed values to be corrupted. - dotnet clean -c Debug - dotnet test -c Debug -f $targetFramework /p:codecov=true + # Allow toggling of profile to workaround any potential JIT errors caused by code injection. + dotnet clean -c $codecovProfile + dotnet test -c $codecovProfile -f $targetFramework /p:codecov=true } elseif ($platform -eq '-x86' -and $targetFramework -match $netFxRegex) { @@ -31,7 +31,7 @@ elseif ($platform -eq '-x86' -and $targetFramework -match $netFxRegex) { Set-Location $PSScriptRoot } -else { +else { dotnet test --no-build -c Release -f $targetFramework } diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index 60c1f4178a..bb4ddb7d0c 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Diagnostics.CodeAnalysis; using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Formats; @@ -19,6 +20,7 @@ namespace SixLabors.ImageSharp.Advanced /// None of the methods in this class should ever be called, the code only has to exist at compile-time to be picked up by the AoT compiler. /// (Very similar to the LinkerIncludes.cs technique used in Xamarin.Android projects.) /// + [ExcludeFromCodeCoverage] internal static class AotCompilerTools { static AotCompilerTools() diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets index 40347763d9..26baee07e3 100644 --- a/tests/Directory.Build.targets +++ b/tests/Directory.Build.targets @@ -29,7 +29,7 @@ true true opencover - + $(MSBuildThisFileDirectory)..\coverage.xml @@ -40,8 +40,8 @@ - - + + diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 34f517500c..edadf711de 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -8,6 +8,7 @@ netcoreapp3.1;netcoreapp2.1;net472 false + false From 1d4887fd3a0385cbb4abaec12cd72545d2793542 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 17 Jan 2020 12:10:37 +1100 Subject: [PATCH 51/53] Update ci-test.ps1 --- ci-test.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ci-test.ps1 b/ci-test.ps1 index c9cfc07a37..fc368b22fb 100644 --- a/ci-test.ps1 +++ b/ci-test.ps1 @@ -35,3 +35,7 @@ else { dotnet test --no-build -c Release -f $targetFramework } + +# Explicitly exit with 0 to ignore errors caused by coverlet attempting to read +# project files that dotnet test is set to ignore. +exit 0 From 3a64f922913f8b1ab898e7720031e544d31af376 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 17 Jan 2020 16:03:23 +1100 Subject: [PATCH 52/53] Fix netstandard 1.3 build --- Directory.Build.props | 45 ++++++++++--------- Directory.Build.targets | 3 -- ImageSharp.sln | 6 +++ shared-infrastructure | 2 +- src/ImageSharp/ImageSharp.csproj | 6 +-- .../ImageSharp.Benchmarks.csproj | 1 - 6 files changed, 33 insertions(+), 30 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index e4e52ac164..cd2f7311ef 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -31,33 +31,36 @@ - - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_RUNTIME_INTRINSICS; + + $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_RUNTIME_INTRINSICS;SUPPORTS_CODECOVERAGE - - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING + + $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_CODECOVERAGE - - $(DefineConstants);SUPPORTS_MATHF; + + $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_CODECOVERAGE - - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING + + $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_CODECOVERAGE - - $(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS + + $(DefineConstants);SUPPORTS_CODECOVERAGE + + + $(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_CODECOVERAGE diff --git a/Directory.Build.targets b/Directory.Build.targets index f69a873acc..eb0764d899 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -24,9 +24,6 @@ - - - diff --git a/ImageSharp.sln b/ImageSharp.sln index 2adc18f46d..875ede1b2d 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -329,7 +329,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ .github\workflows\build-and-test.yml = .github\workflows\build-and-test.yml EndProjectSection EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SharedInfrastructure", "shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.shproj", "{68A8CC40-6AED-4E96-B524-31B1158FDEEA}" +EndProject Global + GlobalSection(SharedMSBuildProjectFiles) = preSolution + shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems*{68a8cc40-6aed-4e96-b524-31b1158fdeea}*SharedItemsImports = 13 + EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 @@ -412,6 +417,7 @@ Global {2BF743D8-2A06-412D-96D7-F448F00C5EA5} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {561B880A-D9EE-44EF-90F5-817C54A9D9AB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {C0D7754B-5277-438E-ABEB-2BA34401B5A7} = {1799C43E-5C54-4A8F-8D64-B1475241DB0D} + {68A8CC40-6AED-4E96-B524-31B1158FDEEA} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5F8B9D1F-CD8B-4CC5-8216-D531E25BD795} diff --git a/shared-infrastructure b/shared-infrastructure index 40f740dea2..36b2d55f5b 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit 40f740dea2aad9dabae12a8e1e17fdcf476066ba +Subproject commit 36b2d55f5bb0d91024955bd26ba220ee41cc96e5 diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index f13989acdc..a6beac7258 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -19,10 +19,6 @@ SixLabors.ImageSharp - - - - True @@ -207,4 +203,6 @@ + + diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index edadf711de..60b1fde8e0 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -21,7 +21,6 @@ - From 2e8f50d8f69db6265e1a484259466e0d43f1f57d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 18 Jan 2020 09:22:57 +1100 Subject: [PATCH 53/53] Temporarily disable Stylecop in tests --- Directory.Build.props | 3 ++- src/Directory.Build.props | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index cd2f7311ef..346da14be8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -102,7 +102,8 @@ - + + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 0bddf7e696..5e3f9b0618 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -25,8 +25,11 @@ true - + + + +