diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..19e6f77 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,39 @@ +name: CI + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +env: + DOTNET_NOLOGO: 1 + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-dotnet@v4 + name: Install Current .NET SDK + - name: Restore dependencies + run: dotnet restore /p:TreatWarningsAsErrors=true + - name: Build + run: dotnet build --configuration Release --no-restore /p:TreatWarningsAsErrors=true + + nupkg: + name: Package + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-dotnet@v4 + name: Install Current .NET SDK + - name: Generate NuGet Packages + run: dotnet pack --configuration Release --output nupkg /p:TreatWarningsAsErrors=true + - uses: actions/upload-artifact@v4 + if: success() && github.ref == 'refs/heads/main' + with: + name: nupkg + path: nupkg/* + retention-days: 1 diff --git a/Polyadic.Build.SemanticVersioning/GenerateSemanticVersionRanges.cs b/Polyadic.Build.SemanticVersioning/GenerateSemanticVersionRanges.cs new file mode 100644 index 0000000..7e4f698 --- /dev/null +++ b/Polyadic.Build.SemanticVersioning/GenerateSemanticVersionRanges.cs @@ -0,0 +1,45 @@ +using Microsoft.Build.Framework; +using NuGet.Versioning; + +namespace Polyadic.Build.SemanticVersioning; + +public sealed class GenerateSemanticVersionRanges : Microsoft.Build.Utilities.Task +{ + [Required] + public ITaskItem[] ProjectReferencesWithVersions { get; set; } = null!; + + public string VersionMetadataName { get; set; } = "ProjectVersion"; + + [Output] + public ITaskItem[] ProjectReferencesWithExactVersions { get; set; } = null!; + + public override bool Execute() + { + foreach (var projectReference in ProjectReferencesWithVersions) + { + var versionString = projectReference.GetMetadata(VersionMetadataName); + + if (!SemanticVersion.TryParse(versionString, out var version)) + { + Log.LogError("'{0}' is not a valid semantic version", versionString); + return false; + } + + projectReference.SetMetadata(VersionMetadataName, ToVersionRange(version)); + } + + ProjectReferencesWithExactVersions = ProjectReferencesWithVersions; + return true; + } + + private static string ToVersionRange(SemanticVersion version) + => version switch + { + /* No SemVer guarantees for pre-release (e.g. nightly) versions, so we use an exact version. */ + { IsPrerelease: true } => $"[{version}]", + /* We use Cargo's convention for 0.x versions i.e. minor = breaking, patch = feature or patch. */ + { Major: 0, Minor: var minor, Patch: var patch } => $"[0.{minor}.{patch}, 0.{minor + 1})", + /* 1.x versions follow regular SemVer rules. */ + { Major: var major, Minor: var minor, Patch: var patch } => $"[{major}.{minor}.{patch}, {major + 1})", + }; +} diff --git a/Polyadic.Build.SemanticVersioning/Polyadic.Build.SemanticVersioning.csproj b/Polyadic.Build.SemanticVersioning/Polyadic.Build.SemanticVersioning.csproj new file mode 100644 index 0000000..dba6458 --- /dev/null +++ b/Polyadic.Build.SemanticVersioning/Polyadic.Build.SemanticVersioning.csproj @@ -0,0 +1,52 @@ + + + netstandard2.0 + enable + enable + 13.0 + + + 1.0.0 + Uses semantic version ranges for ProjectReferences. + readme.md + + + + true + true + $(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage + tasks + true + $(NoWarn);NU5100 + + + + + + + + + + + + + + + + + + + + + diff --git a/Polyadic.Build.SemanticVersioning/buildMultiTargeting/Polyadic.Build.SemanticVersioning.props b/Polyadic.Build.SemanticVersioning/buildMultiTargeting/Polyadic.Build.SemanticVersioning.props new file mode 100644 index 0000000..15c1ba0 --- /dev/null +++ b/Polyadic.Build.SemanticVersioning/buildMultiTargeting/Polyadic.Build.SemanticVersioning.props @@ -0,0 +1,5 @@ + + + + diff --git a/Polyadic.Build.SemanticVersioning/buildMultiTargeting/Polyadic.Build.SemanticVersioning.targets b/Polyadic.Build.SemanticVersioning/buildMultiTargeting/Polyadic.Build.SemanticVersioning.targets new file mode 100644 index 0000000..9dd646b --- /dev/null +++ b/Polyadic.Build.SemanticVersioning/buildMultiTargeting/Polyadic.Build.SemanticVersioning.targets @@ -0,0 +1,13 @@ + + + + + + + + + <_ProjectReferencesWithVersions Remove="@(_ProjectReferencesWithVersions)" /> + <_ProjectReferencesWithVersions Include="@(_ProjectReferencesWithExactVersions)" /> + + + diff --git a/Polyadic.Build.SemanticVersioning/readme.md b/Polyadic.Build.SemanticVersioning/readme.md new file mode 100644 index 0000000..c4171c7 --- /dev/null +++ b/Polyadic.Build.SemanticVersioning/readme.md @@ -0,0 +1,8 @@ +# Polyadic.Build.SemanticVersioning + +> [!CAUTION] +> This package is meant for consumption by Polyadic repositories. +> As such, we may break it at any time. + +Generates semantic version ranges (e.g. `[1.2.0, 2)`) for project +references during `dotnet pack`. diff --git a/Polyadic.Build.sln b/Polyadic.Build.sln index 58ea566..15d8e11 100644 --- a/Polyadic.Build.sln +++ b/Polyadic.Build.sln @@ -3,6 +3,22 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Polyadic.Build.SemanticVersioning", "Polyadic.Build.SemanticVersioning\Polyadic.Build.SemanticVersioning.csproj", "{394028FA-7997-45A2-B4E7-87852BAE577E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build Config", "Build Config", "{84545C75-8BA9-4802-AAE1-C45F0CD258C0}" + ProjectSection(SolutionItems) = preProject + global.json = global.json + Directory.Build.props = Directory.Build.props + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{64E40113-89F8-49B0-B33E-4A99902944E1}" + ProjectSection(SolutionItems) = preProject + readme.md = readme.md + .gitignore = .gitignore + .gitattributes = .gitattributes + .editorconfig = .editorconfig + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -11,4 +27,10 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {394028FA-7997-45A2-B4E7-87852BAE577E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {394028FA-7997-45A2-B4E7-87852BAE577E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {394028FA-7997-45A2-B4E7-87852BAE577E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {394028FA-7997-45A2-B4E7-87852BAE577E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection EndGlobal diff --git a/readme.md b/readme.md index da45bc8..33ed4dd 100644 --- a/readme.md +++ b/readme.md @@ -2,6 +2,11 @@ Shared Build Tools for all Polyadic/Funcky projects. +## Packages + +* **Polyadic.Build.SemanticVersioning**: Generates semantic version ranges for project references. \ + [![NuGet Version](https://img.shields.io/nuget/v/Polyadic.Build.SemanticVersioning)](https://www.nuget.org/packages/Polyadic.Build.SemanticVersioning) + ## License Licensed under either of