diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml
index 5424e2e..674865a 100644
--- a/.github/workflows/ci-build.yml
+++ b/.github/workflows/ci-build.yml
@@ -2,18 +2,19 @@ name: CI Build
run-name: CIBuild_${{ github.event_name }}_${{ github.ref_name }}_${{ github.run_number }}.${{ github.run_attempt }}
env:
- PKG_MAJOR_VERSION: 1.2
+ PKG_MAJOR_VERSION: 1.3
PROJECT_NAME: DNX.Extensions
DOTNET_VERSION: 8.0.x
NUGET_VERSION: 5.x
BUILD_CONFIG: Release
BUILD_PLATFORM: Any CPU
PACK_PARAMETERS: ''
- COVERAGE_WARNING_THRESHOLD: 60
- COVERAGE_ERROR_THRESHOLD: 80
+ COVERAGE_WARNING_THRESHOLD: 95
+ COVERAGE_ERROR_THRESHOLD: 85
NUGET_OUTPUT_FOLDER: nupkgs
BRANCH_PREFIX_RELEASE_CANDIDATE: rc/
BRANCH_PREFIX_PUBLISH_CANDIDATE: beta/
+ BRANCH_NAME_BENCHMARK_CANDIDATE: benchmark
on:
push:
@@ -40,39 +41,79 @@ jobs:
steps:
- name: Get Current Build Date
- id: build_date
run: echo "build_date=$(date +'%y%j')" >> $GITHUB_ENV
- - name: Set Package Suffix
- id: package_suffix
+ - name: Evaluate pipeline conditions
run: |
- branch="${{ github.ref }}"
- package_suffix=''
+ is_primary_branch=false
+ is_pull_request_build=false
+ is_release_candidate_branch=false
+ is_publish_candidate_branch=false
+ is_benchmark_candidate_branch=false
- if [ "$branch" != "refs/heads/main" ]
+ # Primary Branch ?
+ if [ "${{ github.ref }}" == 'refs/heads/main' ]
then
- package_suffix='-beta'
+ is_primary_branch=true
fi
- echo "package_suffix=${package_suffix}" >> $GITHUB_ENV
+ # Pull Request ?
+ if [ "${{ github.event_name }}" == "pull_request" ]
+ then
+ is_pull_request_build=true
+ fi
+
+ # If Release Candidate branch ?
+ if [[ "${{ github.ref }}" == refs/heads/${{ env.BRANCH_PREFIX_RELEASE_CANDIDATE }}* ]]
+ then
+ is_release_candidate_branch=true
+ fi
+
+ # Is Publish Candidate branch ?
+ if [[ "${{ github.ref }}" == refs/heads/${{ env.BRANCH_PREFIX_PUBLISH_CANDIDATE }}* ]]
+ then
+ is_publish_candidate_branch=true
+ fi
+
+ # Is Benchmark Candidate branch ?
+ if [[ "${{ github.ref }}" == *${{ env.BRANCH_NAME_BENCHMARK_CANDIDATE }}* ]]
+ then
+ is_benchmark_candidate_branch=true
+ fi
+
+ # Set for later steps
+ echo "is_primary_branch=${is_primary_branch}" >> $GITHUB_ENV
+ echo "is_pull_request_build=${is_pull_request_build}" >> $GITHUB_ENV
+ echo "is_release_candidate_branch=${is_release_candidate_branch}" >> $GITHUB_ENV
+ echo "is_publish_candidate_branch=${is_publish_candidate_branch}" >> $GITHUB_ENV
+ echo "is_benchmark_candidate_branch=${is_benchmark_candidate_branch}" >> $GITHUB_ENV
+
+ - name: Determine Tagging
+ run: |
+ should_tag=false
+
+ if $is_primary_branch
+ then
+ should_tag=true
+ fi
+
+ echo "should_tag=${should_tag}" >> $GITHUB_ENV
- - name: Determing GitHub Releasing
- id: should_release
+ - name: Determine GitHub Releasing
run: |
should_release=false
release_is_draft=false
release_is_prerelease=false
- if [ "${{ github.ref }}" == 'refs/heads/main' ]
+ if $is_primary_branch
then
should_release=true
- elif [[ "${{ github.ref }}" == refs/heads/${{ env.BRANCH_PREFIX_RELEASE_CANDIDATE }}* ]]
+ elif $is_release_candidate_branch
then
should_release=true
release_is_draft=true
- if [ "${{ github.event_name }}" == "pull_request" ]
- then
+ if $is_pull_request_build; then
release_is_draft=false
release_is_prerelease=true
fi
@@ -82,49 +123,80 @@ jobs:
echo "release_is_draft=${release_is_draft}" >> $GITHUB_ENV
echo "release_is_prerelease=${release_is_prerelease}" >> $GITHUB_ENV
+ - name: Determine Benchmarking
+ run: |
+ should_benchmark=false
+
+ if $should_release
+ then
+ should_benchmark=true
+ elif $is_pull_request_build
+ then
+ should_benchmark=true
+ elif $is_benchmark_candidate_branch
+ then
+ should_benchmark=true
+ fi
+
+ echo "should_benchmark=${should_benchmark}" >> $GITHUB_ENV
+
- name: Determine package publishing
- id: should_publish
run: |
should_publish=false
- if [ "${{ github.event_name }}" == "pull_request" ]
+ if $is_primary_branch
then
should_publish=true
- elif [ "${{ github.ref }}" == "refs/heads/main" ]
+ elif $is_pull_request_build
then
should_publish=true
- elif [[ "${{ github.ref }}" == refs/heads/${{ env.BRANCH_PREFIX_PUBLISH_CANDIDATE }}* ]]
+ elif $is_publish_candidate_branch
then
should_publish=true
fi
echo "should_publish=${should_publish}" >> $GITHUB_ENV
+ - name: Set Package Suffix
+ run: |
+ package_suffix=''
+
+ if !($is_primary_branch)
+ then
+ package_suffix='-beta'
+
+ if $should_release
+ then
+ package_suffix='-rc'
+ fi
+ fi
+
+ echo "package_suffix=${package_suffix}" >> $GITHUB_ENV
+
- name: Set Product Version
- id: product_version
run: echo "product_version=${{ env.PKG_MAJOR_VERSION }}" >> $GITHUB_ENV
- name: Set Assembly Version
- id: assembly_version
run: echo "assembly_version=${{ env.PKG_MAJOR_VERSION }}.${{ env.build_date }}.${{ github.run_number }}${{ github.run_attempt }}" >> $GITHUB_ENV
- name: Set Package Version
- id: package_version
run: echo "package_version=${{ env.assembly_version }}${{ env.package_suffix }}" >> $GITHUB_ENV
- name: Show Configuration
- id: show_configuration
run: env | sort
outputs:
assembly_version: ${{ env.assembly_version }}
product_version: ${{ env.product_version }}
package_version: ${{ env.package_version }}
+ should_tag: ${{ env.should_tag }}
should_publish: ${{ env.should_publish }}
should_release: ${{ env.should_release }}
+ should_benchmark: ${{ env.should_benchmark }}
release_is_draft: ${{ env.release_is_draft }}
release_is_prerelease: ${{ env.release_is_prerelease }}
+
##########################################################
## Build DotNet projects
build:
@@ -160,8 +232,6 @@ jobs:
comment-title: 'Unit Test Results'
results-path: "**/*.trx"
coverage-type: cobertura
- #coverage-path: "**/coverage.cobertura.xml"
- #coverage-threshold: ${{ env.COVERAGE_WARNING_THRESHOLD }}
- name: Code Coverage Report
uses: irongut/CodeCoverageSummary@v1.3.0
@@ -204,8 +274,32 @@ jobs:
path: "${{ env.NUGET_OUTPUT_FOLDER }}/**"
if-no-files-found: error
+
+ ##########################################################
+ ## Tag in git
+ tag:
+ name: Tag in GitHub
+ if: needs.setup.outputs.should_tag == 'true'
+
+ needs:
+ - setup
+ - build
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Tag git
+ uses: pkgdeps/git-tag-action@v3
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ github_repo: ${{ github.repository }}
+ git_commit_sha: ${{ github.sha }}
+ git_tag_prefix: "v"
+ version: ${{ needs.setup.outputs.assembly_version }}
+
+
##########################################################
- ## Generate a Release and Tag in git
+ ## Generate a GitHub Release
release:
name: Create GitHub Release
if: needs.setup.outputs.should_release == 'true'
@@ -226,7 +320,6 @@ jobs:
path: nuget
- name: Build Changelog
- id: build_changelog
uses: mikepenz/release-changelog-builder-action@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -242,14 +335,35 @@ jobs:
removeArtifacts: true
artifacts: '**/*.nupkg'
- - name: Tag git
- uses: pkgdeps/git-tag-action@v3
+
+ ##########################################################
+ ## Benchmark Performance
+ benchmark:
+ name: Benchmark Performance
+ if: needs.setup.outputs.should_benchmark == 'true'
+
+ needs:
+ - setup
+ - build
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Install .NET SDK
+ uses: actions/setup-dotnet@v4
with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- github_repo: ${{ github.repository }}
- git_commit_sha: ${{ github.sha }}
- git_tag_prefix: "v"
- version: ${{ needs.setup.outputs.assembly_version }}
+ dotnet-version: ${{ env.DOTNET_VERSION }}
+
+ - name: Run Benchmarks
+ run: dotnet run --configuration ${{ env.BUILD_CONFIG }} --project tests/DNX.Extensions.Benchmarks
+
+ - name: Publish Benchmark output
+ run: |
+ cat BenchmarkDotNet.Artifacts/results/*Benchmarks-report-github.md >> $GITHUB_STEP_SUMMARY
+
##########################################################
## Publish to NuGet
@@ -271,7 +385,6 @@ jobs:
nuget-version: ${{ env.NUGET_VERSION }}
- name: Download NuGet Output
- id: download_nuget
uses: actions/download-artifact@v4
with:
name: nuget_output
diff --git a/DNX.Extensions.sln b/DNX.Extensions.sln
index dd9ab94..476873c 100644
--- a/DNX.Extensions.sln
+++ b/DNX.Extensions.sln
@@ -24,8 +24,12 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".docs", ".docs", "{8700E3D9-9248-4679-A0E8-8AB3E0B3B09D}"
ProjectSection(SolutionItems) = preProject
LICENSE = LICENSE
+ README.md = README.md
+ To Do.md = To Do.md
EndProjectSection
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DNX.Extensions.Benchmarks", "tests\DNX.Extensions.Benchmarks\DNX.Extensions.Benchmarks.csproj", "{D9664527-B415-498F-B8A9-9AF016D7D91F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -40,6 +44,10 @@ Global
{B14EFA70-CA77-4439-9C08-357061B97E4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B14EFA70-CA77-4439-9C08-357061B97E4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B14EFA70-CA77-4439-9C08-357061B97E4D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D9664527-B415-498F-B8A9-9AF016D7D91F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D9664527-B415-498F-B8A9-9AF016D7D91F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D9664527-B415-498F-B8A9-9AF016D7D91F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D9664527-B415-498F-B8A9-9AF016D7D91F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -47,6 +55,7 @@ Global
GlobalSection(NestedProjects) = preSolution
{E2B8F640-BCFE-4BD7-B158-E7FE957A38CB} = {E832563B-3DD6-4CCD-B5DA-91F89AE3B98A}
{B14EFA70-CA77-4439-9C08-357061B97E4D} = {27BBD260-1C33-4F57-925A-12AB922D6AB5}
+ {D9664527-B415-498F-B8A9-9AF016D7D91F} = {27BBD260-1C33-4F57-925A-12AB922D6AB5}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A971C3D4-3729-43C6-88E7-16371F03161F}
diff --git a/To Do.md b/To Do.md
new file mode 100644
index 0000000..d8ccd16
--- /dev/null
+++ b/To Do.md
@@ -0,0 +1,20 @@
+# TO DO
+
+## Variables with multiple values
+
+- https://github.com/orgs/community/discussions/46785
+
+## Multi Targeting
+
+- https://learn.microsoft.com/en-us/answers/questions/1398343/nuget-how-can-i-make-a-single-nuget-package-target
+- https://runs-on.com/github-actions/the-matrix-strategy/
+- https://github.com/NuGet/setup-nuget
+
+## Better Test Reporting ?
+
+- https://github.com/marketplace/actions/dotnet-test-reporter
+
+## NuGet signing
+
+- https://timheuer.com/blog/use-nuget-with-github-actions-github-packages/
+-
diff --git a/src/DNX.Extensions/DNX.Extensions.csproj b/src/DNX.Extensions/DNX.Extensions.csproj
index c1ca19a..44008b7 100644
--- a/src/DNX.Extensions/DNX.Extensions.csproj
+++ b/src/DNX.Extensions/DNX.Extensions.csproj
@@ -6,6 +6,7 @@
x64;x86;AnyCPU
true
disable
+ true
@@ -19,11 +20,15 @@
favicon-32x32.png
https://raw.githubusercontent.com/martinsmith1968/DNX.Extensions/main/images/favicon-32x32.png
- Interpolation to a working version and some preparation for moving to .NET Standard
+ Migration from DNX.Helpers
+
+ True
+
+
True
diff --git a/src/DNX.Extensions/IO/DirectoryInfoExtensions.cs b/src/DNX.Extensions/IO/DirectoryInfoExtensions.cs
index ce2b1e5..34cab8b 100644
--- a/src/DNX.Extensions/IO/DirectoryInfoExtensions.cs
+++ b/src/DNX.Extensions/IO/DirectoryInfoExtensions.cs
@@ -94,10 +94,12 @@ public static string GetRelativePath(this DirectoryInfo directoryInfo, Directory
: GetRelativePath(directoryInfo.FullName, owningDirectoryInfo.FullName)
.RemoveStartsWith($".{Path.DirectorySeparatorChar}");
+#if NETSTANDARD2_1_OR_GREATER
if (relativePath == ".")
{
relativePath = string.Empty;
}
+#endif
return relativePath;
}
diff --git a/tests/DNX.Extensions.Benchmarks/DNX.Extensions.Benchmarks.csproj b/tests/DNX.Extensions.Benchmarks/DNX.Extensions.Benchmarks.csproj
new file mode 100644
index 0000000..fe5b61f
--- /dev/null
+++ b/tests/DNX.Extensions.Benchmarks/DNX.Extensions.Benchmarks.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+ false
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/DNX.Extensions.Benchmarks/DevelopmentConfig.cs b/tests/DNX.Extensions.Benchmarks/DevelopmentConfig.cs
new file mode 100644
index 0000000..c78f585
--- /dev/null
+++ b/tests/DNX.Extensions.Benchmarks/DevelopmentConfig.cs
@@ -0,0 +1,20 @@
+using System.Diagnostics.CodeAnalysis;
+using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Exporters;
+
+namespace DNX.Extensions.Benchmarks;
+
+[ExcludeFromCodeCoverage]
+internal class DevelopmentConfig : ManualConfig
+{
+ public DevelopmentConfig()
+ {
+ AddExporter(DefaultConfig.Instance.GetExporters().ToArray());
+ AddLogger(DefaultConfig.Instance.GetLoggers().ToArray());
+ AddColumnProvider(DefaultConfig.Instance.GetColumnProviders().ToArray());
+
+ AddExporter(new HtmlExporter());
+
+ WithOptions(ConfigOptions.DisableOptimizationsValidator);
+ }
+}
diff --git a/tests/DNX.Extensions.Benchmarks/Program.cs b/tests/DNX.Extensions.Benchmarks/Program.cs
new file mode 100644
index 0000000..1c8dac1
--- /dev/null
+++ b/tests/DNX.Extensions.Benchmarks/Program.cs
@@ -0,0 +1,21 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+using BenchmarkDotNet.Running;
+
+namespace DNX.Extensions.Benchmarks;
+
+[ExcludeFromCodeCoverage]
+public class Program
+{
+ public static void Main()
+ {
+ BenchmarkRunner.Run(
+ Assembly.GetExecutingAssembly(),
+#if DEBUG
+ new DevelopmentConfig()
+#else
+ null
+#endif
+ );
+ }
+}
diff --git a/tests/DNX.Extensions.Benchmarks/Strings/StringExtensionBenchmarks.cs b/tests/DNX.Extensions.Benchmarks/Strings/StringExtensionBenchmarks.cs
new file mode 100644
index 0000000..312ee2d
--- /dev/null
+++ b/tests/DNX.Extensions.Benchmarks/Strings/StringExtensionBenchmarks.cs
@@ -0,0 +1,41 @@
+using System.Diagnostics.CodeAnalysis;
+using BenchmarkDotNet.Attributes;
+using DNX.Extensions.Strings;
+
+namespace DNX.Extensions.Benchmarks.Strings;
+
+[ExcludeFromCodeCoverage]
+[MemoryDiagnoser]
+[MarkdownExporterAttribute.GitHub]
+public class StringExtensionBenchmarks
+{
+ private const string SearchText = nameof(SearchText);
+
+ private string _text = "";
+
+ [Params(100)]
+ public int StartTextSize { get; set; }
+
+ [Params(100)]
+ public int EndTextSize { get; set; }
+
+ [GlobalSetup]
+ public void GlobalSetup()
+ {
+ _text = string.Format(
+ "{0}{1}{2}",
+ new string('-', StartTextSize),
+ SearchText,
+ new string('-', EndTextSize)
+ );
+ }
+
+ [Benchmark]
+ public string Before() => _text.Before(SearchText);
+
+ [Benchmark]
+ public string After() => _text.After(SearchText);
+
+ [Benchmark]
+ public string Reverse() => _text.Reverse();
+}
diff --git a/tests/DNX.Extensions.Tests/DNX.Extensions.Tests.csproj b/tests/DNX.Extensions.Tests/DNX.Extensions.Tests.csproj
index b861842..a05eff9 100644
--- a/tests/DNX.Extensions.Tests/DNX.Extensions.Tests.csproj
+++ b/tests/DNX.Extensions.Tests/DNX.Extensions.Tests.csproj
@@ -7,6 +7,7 @@
x64;x86;AnyCPU
enable
disable
+ false
diff --git a/tests/DNX.Extensions.Tests/IO/DirectoryInfoExtensionsTests.cs b/tests/DNX.Extensions.Tests/IO/DirectoryInfoExtensionsTests.cs
index f511b91..9055c00 100644
--- a/tests/DNX.Extensions.Tests/IO/DirectoryInfoExtensionsTests.cs
+++ b/tests/DNX.Extensions.Tests/IO/DirectoryInfoExtensionsTests.cs
@@ -246,6 +246,7 @@ public static TheoryData GetRelativePath_Data()
{
{ Path.Combine(Path.GetTempPath(), guid1), null, null },
{ null, Path.Combine(Path.GetTempPath(), guid1), null },
+ { Path.Combine(Path.GetTempPath(), guid1), Path.Combine(Path.GetTempPath(), guid1), "" },
{ Path.Combine(Path.GetTempPath(), guid1), Path.Combine(Path.GetTempPath(), "abcdefg"), Path.Join("..", guid1) },
{ Path.Combine(Path.GetTempPath(), guid2), Path.Combine(Path.GetTempPath(), guid3), Path.Join("..", guid2) },
{ Path.Combine(Path.GetTempPath(), "abcdefg"), Path.Combine(Path.GetTempPath(), "abcdefg"), "" },