diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..0978ab1 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,22 @@ +# Description + + + +# Testing + + + +# Pull Request Type + +Please select the option(s) that are relevant to this PR. + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Improvement (fixing a typo, updating readme, renaming a variable name, etc) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5846b00..3031d32 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,69 +11,84 @@ jobs: runs-on: windows-2022 steps: - uses: actions/checkout@v3 + - name: Install .NET SDK uses: actions/setup-dotnet@v3 with: - dotnet-version: | - 3.1.x - 5.x.x - 6.x.x - 7.x.x + dotnet-version: 7.x.x + - name: Set up dotnet tools run: make install-tools - - name: Check dotnet Style + + - name: Check style with dotnet-format run: make lint - security: - runs-on: windows-2022 + + Security_Code_Scan: + runs-on: windows-latest steps: - uses: actions/checkout@v3 + - name: Install .NET SDK uses: actions/setup-dotnet@v3 with: - dotnet-version: | - 3.1.x - 5.x.x - 6.x.x - 7.x.x - - name: Set up dotnet tools - run: make install-tools + dotnet-version: 7.x.x + + - name: Set up dotnet tools and dependencies + run: make install + - name: Run security analysis run: make scan - # TODO: In the future, we can collect the output logs by enabling Code Scanning and using the pre-built GitHub Action: https://github.com/marketplace/actions/securitycodescan - # https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github#uploading-a-code-scanning-analysis-with-github-actions - coverage: - if: github.ref == 'refs/heads/master' - runs-on: windows-2022 + + Coverage_Requirements: + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 + - name: Install .NET SDK uses: actions/setup-dotnet@v3 with: - dotnet-version: | - 3.1.x - 5.x.x - 6.x.x - 7.x.x + dotnet-version: 7.x.x + + - name: Set up dotnet tools and dependencies + run: make install + + - name: Check if test suite coverage meets requirements + run: make coverage-check + + Upload_Coverage_Report: + if: github.ref == 'refs/heads/master' + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - name: Set up dotnet tools and dependencies run: make install + - name: Generate coverage report run: make coverage + - name: Upload lcov coverage report to Coveralls uses: coverallsapp/github-action@master with: path-to-lcov: coveragereport/lcov.info github-token: ${{ secrets.GITHUB_TOKEN }} + NET_Tests: # derived from https://dev.to/felipetofoli/github-actions-for-net-full-framework-build-and-test-299h runs-on: windows-2022 + env: + EASYPOST_TEST_API_KEY: "123" + EASYPOST_PROD_API_KEY: "123" strategy: matrix: - name: [ 'net462', 'netcoreapp3.1', 'net5.0', 'net6.0', 'net7.0' ] + name: [ 'net462', 'netstandard2.0', 'netcoreapp3.1', 'net5.0', 'net6.0', 'net7.0' ] include: - name: net462 - # This is really a test of .NET Standard, a bridge between .NET Framework and .NET, targeting .NET Framework 4.6.2 + framework: net462 + - name: netstandard2.0 + # can't run tests on .NET Standard, it's just a bridge between .NET Framework and .NET. + # So we'll target .NET Framework 4.6.2 # More notes at the bottom of this file - # Name chosen so we don't have to change the names of the required tests on GitHub Actions framework: net462 - name: netcoreapp3.1 framework: netcoreapp3.1 @@ -87,21 +102,21 @@ jobs: - uses: actions/checkout@v3 with: submodules: true + - name: Install .NET SDK uses: actions/setup-dotnet@v3 with: + # .NET 5 is deprecated and removed from GitHub Actions, we need to manually install it dotnet-version: | - 3.1.x 5.x.x - 6.x.x 7.x.x - # Install MSBuild, used to build the test project + - name: Setup MSBuild uses: microsoft/setup-msbuild@v1.1.2 - # Install NuGet.exe to restore required NuGet packages + - name: Setup Nuget uses: NuGet/setup-nuget@v1.1.1 - # Load NuGet package cache + - name: Load NuGet package cache uses: actions/cache@v3 with: @@ -109,61 +124,83 @@ jobs: key: ${{ runner.os }}-nuget-${{ matrix.framework }}-${{ hashFiles('**/packages.lock.json') }} restore-keys: | ${{ runner.os }}-nuget- - # Restore required NuGet packages + - name: Restore NuGet Packages run: make restore - # Run the framework-specific tests + + # Pull in fixtures submodule + - name: Set up dotnet tools and dependencies + run: make install + + # Run the unit tests in a specific framework (verify that the library works in that framework) - name: Run Tests run: make test-fw fw=${{ matrix.framework }} - Compatibility_Tests: + + FSharp_Compatibility: runs-on: windows-2022 - strategy: - matrix: - lang: [ 'VB', 'FSharp' ] - include: - - lang: VB - ext: vbproj - - lang: FSharp - ext: fsproj steps: - uses: actions/checkout@v3 with: submodules: true + - name: Install .NET SDK uses: actions/setup-dotnet@v3 with: - dotnet-version: | - 3.1.x - 5.x.x - 6.x.x - 7.x.x - # Set the project name, based on platform version currently selected - - name: Set up variables - id: test_project - run: echo "::set-output name=test_file::EasyVCR.Tests.${{ matrix.lang }}" - # Install MSBuild, used to build the test project + dotnet-version: 7.x.x + - name: Setup MSBuild uses: microsoft/setup-msbuild@v1.1.2 - # Install NuGet.exe to restore required NuGet packages + - name: Setup Nuget uses: NuGet/setup-nuget@v1.1.1 - # Install Visual Studio's console test application, to execute tests + - name: Setup VSTest uses: darenm/Setup-VSTest@v1.2 - # Load NuGet package cache - - name: Load NuGet package cache - uses: actions/cache@v3 + + - name: Restore NuGet Packages + run: make restore + + # Pull in fixtures submodule + - name: Set up dotnet tools and dependencies + run: make install + + # Build the test project + - name: Build Solution + run: msbuild EasyVCR.Tests.FSharp\EasyVCR.Tests.FSharp.fsproj /p:platform="Any CPU" /p:configuration="Debug" /p:outputPath="bin/Test" /p:target="Rebuild" -restore + + Visual_Basic_Compatibility: + runs-on: windows-2022 + steps: + + - uses: actions/checkout@v3 with: - path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ matrix.framework }}-${{ hashFiles('**/packages.lock.json') }} - restore-keys: | - ${{ runner.os }}-nuget- - # Restore required NuGet packages + submodules: true + + - name: Install .NET SDK + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 7.x.x + + - name: Setup MSBuild + uses: microsoft/setup-msbuild@v1.1.2 + + - name: Setup Nuget + uses: NuGet/setup-nuget@v1.1.1 + + - name: Setup VSTest + uses: darenm/Setup-VSTest@v1.2 + - name: Restore NuGet Packages run: make restore + + # Pull in fixtures submodule + - name: Set up dotnet tools and dependencies + run: make install + # Build the test project - name: Build Solution - run: msbuild ${{ steps.test_project.outputs.test_file }}\${{ steps.test_project.outputs.test_file }}.${{ matrix.ext }} /p:platform="Any CPU" /p:configuration="Debug" /p:outputPath="bin/Test" /p:target="Rebuild" -restore + run: msbuild EasyVCR.Tests.VB\EasyVCR.Tests.VB.vbproj /p:platform="Any CPU" /p:configuration="Debug" /p:outputPath="bin/Test" /p:target="Rebuild" -restore + # .NET Standard notes: # - NET Standard 2.0 is compatible with minimum .NET Framework 4.6.1: https://docs.microsoft.com/en-us/dotnet/standard/net-standard?tabs=net-standard-2-0 diff --git a/EasyPost.pub b/EasyPost.pub deleted file mode 100644 index a444a81..0000000 Binary files a/EasyPost.pub and /dev/null differ diff --git a/EasyPostNETStrongNameSigning.pub b/EasyPostNETStrongNameSigning.pub new file mode 100644 index 0000000..26cb33c Binary files /dev/null and b/EasyPostNETStrongNameSigning.pub differ diff --git a/EasyVCR/EasyVCR.csproj b/EasyVCR/EasyVCR.csproj index 692ae39..50ff3fb 100644 --- a/EasyVCR/EasyVCR.csproj +++ b/EasyVCR/EasyVCR.csproj @@ -43,7 +43,7 @@ true true - ..\EasyPost.pub + ..\EasyPostNETStrongNameSigning.pub diff --git a/Makefile b/Makefile index 6c949a1..d15fc08 100644 --- a/Makefile +++ b/Makefile @@ -2,19 +2,23 @@ help: @cat Makefile | grep '^## ' --color=never | cut -c4- | sed -e "`printf 's/ - /\t- /;'`" | column -s "`printf '\t'`" -t +## analyze - Run static analysis for the project (check CA rule violations) +analyze: + dotnet build EasyVCR/EasyVCR.csproj -c "Release" -t:Rebuild -restore -p:EnableNETAnalyzers=true -p:CodeAnalysisTreatWarningsAsErrors=true -p:RunAnalyzersDuringBuild=true -p:AnalysisLevel=latest -p:AnalysisMode=Minimum + ## build - Build the project in Debug mode build: - dotnet msbuild -property:Configuration="Debug" -target:Rebuild -restore + dotnet build EasyVCR/EasyVCR.csproj -c "Debug" -t:Rebuild -restore -p:EnableNETAnalyzers=false -## build-test-fw - Build the project for unit testing in Debug mode for a specific framework +## build-fw - Build the project in Debug mode for a specific framework # @parameters: # fw= - The framework to build for. -build-test-fw: - dotnet msbuild EasyVCR.Tests/EasyVCR -property:Configuration="Debug" -target:Rebuild -restore -property:TargetFramework=${fw} +build-fw: + dotnet build EasyVCR/EasyVCR.csproj -c "Debug" -t:Rebuild -restore -f ${fw} -p:EnableNETAnalyzers=false ## build-prod - Build the project in Release mode build-prod: - dotnet msbuild -property:Configuration="Release" -target:Rebuild -restore + dotnet build EasyVCR/EasyVCR.csproj -c "Release" -t:Rebuild -restore -p:EnableNETAnalyzers=false ## clean - Clean the project clean: @@ -23,58 +27,54 @@ clean: ## coverage - Generate coverage reports for the project coverage: - ./generate_test_reports.sh + bash scripts/unix/generate_test_reports.sh + +## coverage-check - Check if the coverage is above the minimum threshold +coverage-check: + bash scripts/unix/check_coverage.sh 88 + +## docs - Generates library documentation +docs: + dotnet tool run docfx docs/docfx.json ## format - Formats the project format: - dotnet dotnet-format --no-restore - -## install-cert - Install the PFX certificate to your system (Windows only) -# @parameters: -# cert= - The certificate to use for signing the built assets. -# pass= - The password for the certificate. -install-cert: - scripts\install_cert.bat ${cert} ${pass} + dotnet tool run dotnet-format --no-restore ## install-tools - Install required dotnet tools install-tools: dotnet new tool-manifest || exit 0 dotnet tool install --local security-scan --version 5.6.3 || exit 0 dotnet tool install --local dotnet-format || exit 0 + dotnet tool install --local docfx --version 2.60.2 || exit 0 + +## install-release-tools - Install required tools for release +install-release-tools: + bash scripts/unix/install_osslsigncode.sh ## install - Install requirements install: | install-tools git submodule init git submodule update -## lint - Lints the project +## lint - Lints the solution (EasyVCR + Tests + F#/VB samples) (check IDE and SA rule violations) lint: - dotnet dotnet-format --no-restore --check + # Lint the source code with dotnet-format + dotnet tool run dotnet-format --no-restore --check + # Lint the source code by building with the "Linting" configuration (will trigger StyleCop) + dotnet build EasyVCR/EasyVCR.csproj -c "Linting" -t:Rebuild -restore -p:EnforceCodeStyleInBuild=true ## lint-scripts - Lint and validate the Batch scripts (Windows only) lint-scripts: - scripts\lint_scripts.bat + scripts\win\lint_scripts.bat -## prep-release - Build, sign and package the project for distribution, signing with the provided certificate (Windows only) +## prep-release - Build, sign and package the project for distribution, signing with the provided certificate # @parameters: -# cert= - The certificate to use for signing the built assets. -# pass= - The password for the certificate. +# sncert= - The strong-name certificate to use for signing the built assets. +# cert= - The authenticity certificate to use for signing the built assets. +# pass= - The password for the authenticity certificate. prep-release: - scripts\build_release_nuget.bat EasyVCR ${cert} ${pass} EasyPost Release - -## publish-all - Publish all NuGet files to nuget.org. -# WARNING: Will publish ALL discovered NuGet files. -# @parameters: -# key= - The API key for nuget.org -publish-all: - scripts\publish_all_nuget.bat ${key} - -## publish - Publish a specific NuGet file to nuget.org (Windows only) -# @parameters: -# file= - The NuGet file to publish -# key= - The API key for nuget.org -publish: - scripts\publish_nuget.bat ${file} ${key} + bash scripts/unix/build_release_nuget.sh EasyVCR ${sncert} ${cert} ${pass} Release ## release - Cuts a release for the project on GitHub (requires GitHub CLI) # tag = The associated tag title of the release @@ -85,27 +85,18 @@ release: restore: dotnet restore -## scan - Scan the project for security issues (must run install-scanner first) -# Makefile cannot access global dotnet tools, so you need to run the below command manually. +## scan - Scan the solution (EasyVCR + Tests + F#/VB samples) for security issues (must run install-scanner first) scan: dotnet tool run security-scan --verbose --no-banner --ignore-msbuild-errors EasyVCR.sln # "--ignore-msbuild-errors" needed since MSBuild does not like F#: https://github.com/security-code-scan/security-code-scan/issues/235 ## setup-win - Install required .NET versions and tools (Windows only) setup-win: - scripts\setup.bat + scripts\win\setup.bat ## setup-unix - Install required .NET versions and tools (Unix only) setup-unix: - bash scripts/setup.sh - -## sign - Sign all generated DLLs and NuGet packages with the provided certificate (Windows only) -# @parameters: -# cert= - The certificate to use for signing the built assets. -# pass= - The password for the certificate. -sign: - install-cert cert=${cert} pass=${pass} - scripts\sign_assemblies.bat ${cert} ${pass} EasyPost + bash scripts/unix/setup.sh ## test - Test the project test: @@ -118,8 +109,4 @@ test-fw: # Note, running .NET Framework tests on a non-Windows machine may cause issues: https://xunit.net/docs/getting-started/netfx/cmdline dotnet test EasyVCR.Tests/EasyVCR.Tests.csproj -f ${fw} -## uninstall-scanner - Uninstall SecurityCodeScan from your system -uninstall-scanner: - dotnet tool uninstall security-scan - -.PHONY: help build build-test-fw build-prod clean coverage format install-cert install-tools install lint lint-scripts pre-release publish-all publish release restore scan setup-unix setup-win sign test test-fw uninstall-scanner \ No newline at end of file +.PHONY: help analyze build build-fw build-prod clean coverage coverage-check docs format install-tools install-release-tools install lint lint-scripts prep-release release restore scan setup-win setup-unix test test-fw diff --git a/certificate info.txt b/certificate info.txt deleted file mode 100644 index 203a098..0000000 --- a/certificate info.txt +++ /dev/null @@ -1,12 +0,0 @@ -Build in Release mode (signs with SNK file during build) - -Validate with Strong Type tool: https://github.com/brutaldev/StrongNameSigner - -Sign each DLL with PFX file: signtool sign /f EasyPost.pfx /p PASSWORD /v /tr http://timestamp.digicert.com?alg=sha256 /td SHA256 /fd SHA256 FILE_PATH -(https://www.tbs-certificates.co.uk/FAQ/en/550.html) - -Check for Digital Signature in File Explorer details - -Package into Nuget file - -Sign Nuget file with PFX via nuget sign \ No newline at end of file diff --git a/generate_test_reports.sh b/generate_test_reports.sh deleted file mode 100755 index 18d2696..0000000 --- a/generate_test_reports.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -# install reportgenerator if not already installed -dotnet tool install --global dotnet-reportgenerator-globaltool --version 5.1.10 || true # exit 0 will kill the script, not what we want - -# check requirements -set -- dotnet reportgenerator -for req in "$@"; do - if ! command -v "$req" >/dev/null 2>&1; then - echo "$req could not be found" - exit - fi -done - -# Generate Cobertura report for each test project -test_folder="EasyVCR.Tests" -cd "$test_folder" || exit -dotnet test --collect:"XPlat Code Coverage" - -# Generate HTML and lcov report -reportgenerator -reports:TestResults/*/coverage.cobertura.xml -targetdir:../coveragereport -reporttypes:Html -reportgenerator -reports:TestResults/*/coverage.cobertura.xml -targetdir:../coveragereport -reporttypes:lcov diff --git a/scripts/install_cert.bat b/scripts/install_cert.bat deleted file mode 100644 index a55f7e1..0000000 --- a/scripts/install_cert.bat +++ /dev/null @@ -1,28 +0,0 @@ -:: This script will install a provided PFX certificate to the system. - -:: Requirements: -:: - dotnet is installed on the machine and is accessible everywhere (added to PATH) (might be in C:\Program Files\dotnet) -:: - SnInstallPfx (https://github.com/honzajscz/SnInstallPfx) is installed on the machine and is accessible everywhere (added to PATH) - -@ECHO OFF - -:: Parse command line arguments -SET certFile=%1 -SET certPass=%2 -SET containerName=%3 - -:: Install certificate -@ECHO: -@ECHO (Re-)Installing certificate to system... -sn -d %containerName% -SnInstallPfx %certFile% %certPass% %containerName% || GOTO :commandFailed - -EXIT /B 0 - -:commandFailed -@ECHO Command failed. -GOTO :exitWithError - -:exitWithError -@ECHO Exiting... -EXIT /B 1 diff --git a/scripts/publish_all_nuget.bat b/scripts/publish_all_nuget.bat deleted file mode 100644 index 9163a47..0000000 --- a/scripts/publish_all_nuget.bat +++ /dev/null @@ -1,27 +0,0 @@ -:: This script will find and publish any NuGet packages to Nuget.org - -:: Requirements: -:: - NuGet is installed on the machine and is accessible everywhere (added to PATH) - -@ECHO OFF - -:: Parse command line arguments -SET apiKey=%1 - -:: Find all NuGet packages -@ECHO: -@ECHO Finding NuGet package(s)... -FOR /R %%F IN (*.nupkg) DO ( - @ECHO Found %%F. Publishing... - nuget push "%%F" -src https://api.nuget.org/v3/index.json -ApiKey %apiKey% -) - -EXIT /B 0 - -:commandFailed -@ECHO Command failed. -GOTO :exitWithError - -:exitWithError -@ECHO Exiting... -EXIT /B 1 diff --git a/scripts/unix/build_project.sh b/scripts/unix/build_project.sh new file mode 100755 index 0000000..cb63f26 --- /dev/null +++ b/scripts/unix/build_project.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# This script will restore and build a .NET project in a specified mode and platform. + +# Requirements: +# - dotnet is installed on the machine and is accessible everywhere (added to PATH) + +# Parse command line arguments +BUILD_MODE=$1 + +# Restore dependencies and build solution +echo "Restoring and building project..." +dotnet msbuild -property:Configuration="$BUILD_MODE" -target:Rebuild -restore || exit 1 diff --git a/scripts/unix/build_release_nuget.sh b/scripts/unix/build_release_nuget.sh new file mode 100755 index 0000000..33f119c --- /dev/null +++ b/scripts/unix/build_release_nuget.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# This script will build a .NET project in Release mode, sign the generated DLLs with a provided PFX certificate, +# package the DLLs into a NuGet package, and sign the NuGet package with the provided PFX certificate. +# This script also handles pre-run cleanup (will delete old DLLs and NuGet package files) + +# Requirements: +# - NuGet is installed on the machine and is accessible everywhere (added to PATH) +# - dotnet is installed on the machine and is accessible everywhere (added to PATH) +# - osslsigncode (https://github.com/mtrojnar/osslsigncode) is installed on the machine and is accessible everywhere (added to PATH) + +# Parse command line arguments +PROJECT_NAME=$1 +STRONG_NAME_CERT_FILE=$2 +AUTH_CERT_FILE=$3 +AUTH_CERT_PASSWORD=$4 +BUILD_MODE=$5 + +# Delete old files +bash scripts/unix/delete_old_assemblies.sh + +# Restore dependencies and build solution +bash scripts/unix/build_project.sh "$BUILD_MODE" || exit 1 + +# Strong-name sign the DLLs +bash scripts/unix/strong_name_dlls.sh "$STRONG_NAME_CERT_FILE" || exit 1 + +# Sign the DLLs for authenticity +bash scripts/unix/sign_dlls.sh "$AUTH_CERT_FILE" "$AUTH_CERT_PASSWORD" || exit 1 + +# Package the DLLs into a NuGet package (will fail if DLLs are missing) +bash scripts/unix/pack_nuget.sh "$PROJECT_NAME" || exit 1 + +# Sign the NuGet package for authenticity +bash scripts/unix/sign_nuget.sh "$AUTH_CERT_FILE" "$AUTH_CERT_PASSWORD" || exit 1 + +# Preset final information +NUGET_PACKAGE_FILE=$(find lib -name "*.nupkg") +echo "NuGet file $NUGET_PACKAGE_FILE is ready." diff --git a/scripts/unix/check_coverage.sh b/scripts/unix/check_coverage.sh new file mode 100755 index 0000000..39cb0b8 --- /dev/null +++ b/scripts/unix/check_coverage.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +FRAMEWORK="net7.0" + +THRESHOLD=$1 +THRESHOLD_TYPE=line + + +# Navigate to the test folder +TEST_FOLDER="EasyVCR.Tests" +cd "$TEST_FOLDER" || exit + +# Coverlet as a global tool does not report coverage properly (https://github.com/coverlet-coverage/coverlet/blob/2b8a4565b101ca70c3eaa9b5228c449dd3b81ad1/Documentation/GlobalTool.md) +# Instead, use the coverlet.msbuild package +# https://codeburst.io/code-coverage-in-net-core-projects-c3d6536fd7d7 +# This will fail to run on machines without MSBuild installed + +# If the coverage is below the threshold, exit with a non-zero exit code +dotnet test -p:CollectCoverage=true -p:CoverletOutput=TestResults/ -f $FRAMEWORK -p:Threshold="$THRESHOLD" -p:ThresholdType=$THRESHOLD_TYPE diff --git a/scripts/unix/delete_old_assemblies.sh b/scripts/unix/delete_old_assemblies.sh new file mode 100755 index 0000000..de420d3 --- /dev/null +++ b/scripts/unix/delete_old_assemblies.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# This script will delete any DLLs and NuGet packages + +# Delete old DLLs +echo "Cleaning old files..." +rm -rf lib +rm -rf "*.nupkg" diff --git a/scripts/unix/generate_test_reports.sh b/scripts/unix/generate_test_reports.sh new file mode 100755 index 0000000..6d70eac --- /dev/null +++ b/scripts/unix/generate_test_reports.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +FRAMEWORK="net7.0" + +# Navigate to the test folder +TEST_FOLDER="EasyVCR.Tests" +cd "$TEST_FOLDER" || exit + +RESULTS_FOLDER="TestResults" + +# Delete old test results +rm -rf "$RESULTS_FOLDER" + +# Generate coverage report +# https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-test#:~:text=To%20collect%20code%20coverage%20on%20any%20platform%20that%20is%20supported%20by%20.NET%20Core%2C +dotnet test --collect:"XPlat Code Coverage" -f $FRAMEWORK + +# install reportgenerator if not already installed +dotnet tool install --global dotnet-reportgenerator-globaltool --version 5.1.10 || true # exit 0 will kill the script, not what we want + +# check reportgenerator is available +set -- dotnet reportgenerator +for req in "$@"; do + if ! command -v "$req" >/dev/null 2>&1; then + echo "$req could not be found" + exit + fi +done + +COVERAGE_REPORT_FOLDER="../coveragereport" + +# Delete old coverage reports +rm -rf "$COVERAGE_REPORT_FOLDER" + +# Generate HTML and lcov report +reportgenerator -reports:$RESULTS_FOLDER/*/coverage.cobertura.xml -targetdir:$COVERAGE_REPORT_FOLDER -reporttypes:Html +reportgenerator -reports:$RESULTS_FOLDER/*/coverage.cobertura.xml -targetdir:$COVERAGE_REPORT_FOLDER -reporttypes:lcov diff --git a/scripts/unix/install_osslsigncode.sh b/scripts/unix/install_osslsigncode.sh new file mode 100644 index 0000000..f5c6eb3 --- /dev/null +++ b/scripts/unix/install_osslsigncode.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# This script will install the osslsigncode dependency (https://github.com/mtrojnar/osslsigncode) required to release this project + +PATH_STORAGE=/usr/local/bin + +# Create a temporary folder +TEMP_FOLDER="temp" +mkdir -p "$TEMP_FOLDER" +cd "$TEMP_FOLDER" || exit + +# Download the latest macOS release +# Courtesy: https://gist.github.com/steinwaywhw/a4cd19cda655b8249d908261a62687f8 +REPO="mtrojnar/osslsigncode" +curl -s https://api.github.com/repos/$REPO/releases/latest \ +| grep "browser_download_url.*macOS.zip" \ +| cut -d : -f 2,3 \ +| tr -d \" \ +| wget -qi - + +# Find the file name of the downloaded file +ZIP_FILE=$(find . -name "*macOS.zip") + +# Unzip the file +unzip "$ZIP_FILE" + +# Find the executable +OSSLSIGNCODE_EXE=$(find . -name "osslsigncode") + +# Make the executable executable +chmod +x "$OSSLSIGNCODE_EXE" + +# Move the executable to the PATH_STORAGE folder +mv "$OSSLSIGNCODE_EXE" "$PATH_STORAGE" + +# Clean up +cd .. +rm -rf "$TEMP_FOLDER" diff --git a/scripts/unix/pack_nuget.sh b/scripts/unix/pack_nuget.sh new file mode 100755 index 0000000..186efb3 --- /dev/null +++ b/scripts/unix/pack_nuget.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# This script will generate a NuGet package according the the project's .nuspec file. + +# Requirements: +# - NuGet is installed on the machine and is accessible everywhere (added to PATH) + +# Parse command line arguments +PROJECT_NAME=$1 + +# Generate the NuGet package (will fail if assemblies are missing) +echo "Generating NuGet package..." +nuget pack "$PROJECT_NAME.nuspec" || exit 1 diff --git a/scripts/setup.sh b/scripts/unix/setup.sh similarity index 76% rename from scripts/setup.sh rename to scripts/unix/setup.sh index a93e21c..b6bbf60 100644 --- a/scripts/setup.sh +++ b/scripts/unix/setup.sh @@ -3,7 +3,7 @@ # This script is used to download and install the required .NET versions # .NET versions we want to install -declare -a NetVersions=("Current" "6.0" "5.0" "3.1") +declare -a NetVersions=("Current" "7.0" "6.0" "5.0" "3.1") # Download dotnet-install.sh echo "Downloading dotnet-install.sh script..." @@ -12,8 +12,8 @@ curl -sSL https://dot.net/v1/dotnet-install.sh -o dotnet-install.sh # Install each .NET version echo "Installing .NET versions..." for version in ${NetVersions[@]}; do - echo "Installing .NET $version..." - sudo bash ./dotnet-install.sh -c "$version" + echo "Installing .NET $version..." + sudo bash ./dotnet-install.sh -c "$version" done # Remove dotnet-install.sh diff --git a/scripts/unix/sign_dlls.sh b/scripts/unix/sign_dlls.sh new file mode 100755 index 0000000..c4e2f29 --- /dev/null +++ b/scripts/unix/sign_dlls.sh @@ -0,0 +1,23 @@ +# Parse command line arguments +CERT_FILE=$1 +CERT_PASSWORD=$2 + +# Set variables +AUTHOR_NAME="EasyPost" +AUTHOR_URL="http://www.easypost.com" +TIMESTAMP_SERVER="http://timestamp.digicert.com?alg=sha256" +FOLDER="lib" +SUFFIX=".signed" +FILE_PATTERN="*.dll" + +# Sign all DLLs found with our certificate to guarantee authenticity +echo "Signing DLLs with $CERT_FILE for authenticity..." +for file in $(find "$FOLDER" -name "$FILE_PATTERN"); do + echo "Signing $file..." + # Sign the file to a new file with added suffix + osslsigncode sign -pkcs12 "$CERT_FILE" -pass "$CERT_PASSWORD" -n "$AUTHOR_NAME" -i "$AUTHOR_URL" -ts "$TIMESTAMP_SERVER" -in "$file" -out "$file$SUFFIX" + # Delete original file + rm -f "$file" + # Rename signed file to original name + mv "$file$SUFFIX" "$file" +done diff --git a/scripts/unix/sign_nuget.sh b/scripts/unix/sign_nuget.sh new file mode 100755 index 0000000..b3ea7ff --- /dev/null +++ b/scripts/unix/sign_nuget.sh @@ -0,0 +1,21 @@ +# This script will find and sign any NuGet packages with a provided PFX certificate for authenticity + +# Requirements: +# - NuGet is installed on the machine and is accessible everywhere (added to PATH) + +# Parse command line arguments +CERT_FILE=$1 +CERT_PASSWORD=$2 + +# Set variables +TIMESTAMP_SERVER="http://timestamp.digicert.com?alg=sha256" +FOLDER="." +FILE_PATTERN="*.nupkg" + +# Sign all NuGet packages found with our certificate to guarantee authenticity +echo "Signing NuGet packages with $CERT_FILE for authenticity..." +# Should only be one .nupkg file at this point, since we deleted the old ones +for file in $(find "$FOLDER" -name "$FILE_PATTERN"); do + # Sign the file in-place + dotnet nuget sign "$file" --timestamper "$TIMESTAMP_SERVER" --certificate-path "$CERT_FILE" --certificate-password "$CERT_PASSWORD" +done diff --git a/scripts/unix/strong_name_dlls.sh b/scripts/unix/strong_name_dlls.sh new file mode 100755 index 0000000..b6920de --- /dev/null +++ b/scripts/unix/strong_name_dlls.sh @@ -0,0 +1,20 @@ +# This script will find and finish strong-naming any DLLs with a provided PFX certificate + +# Requirements: +# - dotnet is installed on the machine and is accessible everywhere (added to PATH) +# - sn is installed on the machine and is accessible everywhere (added to PATH) + +# Parse command line arguments +CERT_FILE=$1 + +# Set variables +FOLDER="lib" +FILE_PATTERN="*.dll" + +# Strong-name all DLLs found in the lib folder +echo "Strong-naming (finishing delayed signing) DLLs with $CERT_FILE..." +for file in $(find "$FOLDER" -name "$FILE_PATTERN"); do + echo "Strong-naming $file..." + # Strong-name the file to a new file with added suffix + sn -R "$file" "$CERT_FILE" +done diff --git a/scripts/build_project.bat b/scripts/win/build_project.bat similarity index 100% rename from scripts/build_project.bat rename to scripts/win/build_project.bat diff --git a/scripts/build_release_nuget.bat b/scripts/win/build_release_nuget.bat similarity index 58% rename from scripts/build_release_nuget.bat rename to scripts/win/build_release_nuget.bat index 6405d40..2ee1f2e 100644 --- a/scripts/build_release_nuget.bat +++ b/scripts/win/build_release_nuget.bat @@ -5,34 +5,33 @@ :: Requirements: :: - NuGet is installed on the machine and is accessible everywhere (added to PATH) :: - dotnet is installed on the machine and is accessible everywhere (added to PATH) (might be in C:\Program Files\dotnet) -:: - SnInstallPfx (https://github.com/honzajscz/SnInstallPfx) is installed on the machine and is accessible everywhere (added to PATH) @ECHO OFF :: Parse command line arguments SET projectName=%1 -SET certFile=%2 -SET certPass=%3 -SET containerName=%4 +SET strongNameCertFile=%2 +SET authCertFile=%3 +SET authCertPass=%4 SET buildMode=%5 :: Delete old files -CALL "scripts\delete_old_assemblies.bat" - -:: Install certificate (needed to automate signing later on) -CALL "scripts\install_cert.bat" %certFile% %certPass% %containerName% || GOTO :commandFailed +CALL "scripts\win\delete_old_assemblies.bat" :: Restore dependencies and build solution -CALL "scripts\build_project.bat" %buildMode% || GOTO :commandFailed +CALL "scripts\win\build_project.bat" %buildMode% || GOTO :commandFailed + +:: Strong-name the DLLs +CALL "scripts\win\strong_name_dlls.bat" %strongNameCertFile% || GOTO :commandFailed -:: Sign the DLLs -CALL "scripts\sign_dlls.bat" %certFile% %certPass% %containerName% || GOTO :commandFailed +:: Sign the DLLs for authenticity +CALL "scripts\win\sign_dlls.bat" %authCertFile% %authCertPass% || GOTO :commandFailed :: Package the DLLs in a NuGet package (will fail if DLLs are missing) -CALL "scripts\pack_nuget.bat" %projectName% || GOTO :commandFailed +CALL "scripts\win\pack_nuget.bat" %projectName% || GOTO :commandFailed -:: Sign the NuGet package -CALL "scripts\sign_nuget.bat" %certFile% %certPass% || GOTO :commandFailed +:: Sign the NuGet package for authenticity +CALL "scripts\win\sign_nuget.bat" %authCertFile% %authCertPass% || GOTO :commandFailed SET nugetFileName= FOR /R %%F IN (*.nupkg) DO ( SET nugetFileName="%%F" @@ -51,7 +50,7 @@ GOTO :eof :usage @ECHO: -@ECHO Usage: %0 +@ECHO Usage: %0 GOTO :exitWithError :commandFailed diff --git a/scripts/delete_old_assemblies.bat b/scripts/win/delete_old_assemblies.bat similarity index 100% rename from scripts/delete_old_assemblies.bat rename to scripts/win/delete_old_assemblies.bat diff --git a/scripts/lint_scripts.bat b/scripts/win/lint_scripts.bat similarity index 100% rename from scripts/lint_scripts.bat rename to scripts/win/lint_scripts.bat diff --git a/scripts/pack_nuget.bat b/scripts/win/pack_nuget.bat similarity index 90% rename from scripts/pack_nuget.bat rename to scripts/win/pack_nuget.bat index 39aae30..3d77ac2 100644 --- a/scripts/pack_nuget.bat +++ b/scripts/win/pack_nuget.bat @@ -5,6 +5,9 @@ @ECHO OFF +:: Parse command line arguments +SET projectName=%1 + :: Generate a NuGet package (will fail if assemblies are missing) @ECHO: @ECHO Generating NuGet package... diff --git a/scripts/publish_nuget.bat b/scripts/win/publish_nuget.bat similarity index 100% rename from scripts/publish_nuget.bat rename to scripts/win/publish_nuget.bat diff --git a/scripts/setup.bat b/scripts/win/setup.bat similarity index 97% rename from scripts/setup.bat rename to scripts/win/setup.bat index 13a95e1..310e44f 100644 --- a/scripts/setup.bat +++ b/scripts/win/setup.bat @@ -10,7 +10,7 @@ @ECHO OFF :: .NET Versions we want to install and destination -SET NetVersions=Current 6.0 5.0 3.1 +SET NetVersions=Current 7.0 6.0 5.0 3.1 SET InstallPath=C:\dotnet :: Dependency file diff --git a/scripts/sign_dlls.bat b/scripts/win/sign_dlls.bat similarity index 63% rename from scripts/sign_dlls.bat rename to scripts/win/sign_dlls.bat index 6e7a152..faaed89 100644 --- a/scripts/sign_dlls.bat +++ b/scripts/win/sign_dlls.bat @@ -1,22 +1,19 @@ -:: This script will find and sign any DLLs with a provided PFX certificate +:: This script will find and sign any DLLs with a provided PFX certificate for authenticity :: Requirements: :: - dotnet is installed on the machine and is accessible everywhere (added to PATH) (might be in C:\Program Files\dotnet) +:: - signtool is installed on the machine and is accessible everywhere (added to PATH) (might be in C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64) @ECHO OFF :: Parse command line arguments SET certFile=%1 SET certPass=%2 -SET containerName=%3 -:: Sign all DLLs found in the lib folder +:: Sign all DLLs found in the lib folder with our certificate to guarantee authenticity @ECHO: -@ECHO Signing DLLs with certificate... +@ECHO Signing DLLs with %certFile% for authenticity... FOR /R "lib" %%F IN (*.dll) DO ( - REM We need to run the DLLs through both sn.exe and signtool to get complete the signing process - REM sn erroneously triggers command failed if we put a fallback on this - sn -Rca "%%F" %containerName% signtool sign /f %certFile% /p %certPass% /v /tr http://timestamp.digicert.com?alg=sha256 /td SHA256 /fd SHA256 "%%F" || GOTO :commandFailed ) diff --git a/scripts/sign_nuget.bat b/scripts/win/sign_nuget.bat similarity index 77% rename from scripts/sign_nuget.bat rename to scripts/win/sign_nuget.bat index 4b109c4..c7190c3 100644 --- a/scripts/sign_nuget.bat +++ b/scripts/win/sign_nuget.bat @@ -1,4 +1,4 @@ -:: This script will find and sign any NuGet packages with a provided PFX certificate +:: This script will find and sign any NuGet packages with a provided PFX certificate for authenticity :: Requirements: :: - NuGet is installed on the machine and is accessible everywhere (added to PATH) @@ -9,9 +9,9 @@ SET certFile=%1 SET certPass=%2 -:: Sign all NuGet packages found +:: Sign all NuGet packages found with our certificate to guarantee authenticity @ECHO: -@ECHO Signing NuGet package with %certFile%... +@ECHO Signing NuGet package with %certFile% for authenticity... :: Should only be one .nupkg file at this point, since we deleted the old ones FOR /R %%F IN (*.nupkg) DO ( nuget sign "%%F" -Timestamper http://timestamp.digicert.com -CertificatePath "%certFile%" -CertificatePassword "%certPass%" || GOTO :commandFailed diff --git a/scripts/win/strong_name_dlls.bat b/scripts/win/strong_name_dlls.bat new file mode 100644 index 0000000..4d44c20 --- /dev/null +++ b/scripts/win/strong_name_dlls.bat @@ -0,0 +1,28 @@ +:: This script will find and finish strong-naming any DLLs with a provided PFX certificate + +:: Requirements: +:: - dotnet is installed on the machine and is accessible everywhere (added to PATH) (might be in C:\Program Files\dotnet) +:: - sn.exe is installed on the machine and is accessible everywhere (added to PATH) + +@ECHO OFF + +:: Parse command line arguments +SET certFile=%1 + +:: Strong-name all DLLs found in the lib folder +@ECHO: +@ECHO Strong-naming (finishing delayed signing) DLLs with %certFile%... +FOR /R "lib" %%F IN (*.dll) DO ( + REM sn erroneously triggers command failed if we put a fallback on this + sn -Ra "%%F" %certFile% +) + +EXIT /B 0 + +:commandFailed +@ECHO Command failed. +GOTO :exitWithError + +:exitWithError +@ECHO Exiting... +EXIT /B 1