Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ dotnet build # Build everything
dotnet test # Run all tests
dotnet test --filter "ClassName=RangeContainsTests" # Single test class
dotnet test --filter "FullyQualifiedName~Contains_FiniteRange" # Single method
dotnet build -c Release && dotnet pack -c Release --no-build # Pack NuGet packages
dotnet pack -c Release # Pack NuGet packages (builds first)
```

`dotnet pack` on its own fails with `NU5026`: `GeneratePackageOnBuild` makes pack race the
compile. Build first, then pack with `--no-build`.
The build treats warnings as errors (`Directory.Build.props`), including CS1591 on the public
surface of the shipping projects — the shipped `.xml` is what IntelliSense shows. Deliberate
internal-API usage (EF1001) is acknowledged with a file-level pragma next to the reason, never
repo-wide.

## Workflow
1. Read `docs/architecture.md` before modifying range types or interfaces
Expand Down
32 changes: 31 additions & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,42 @@
<Authors>CaffeinatedCoder</Authors>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<PackageProjectUrl>https://github.com/CaffeinatedCoder/CodoMetis.ValueRanges</PackageProjectUrl>
<RepositoryUrl>https://github.com/CaffeinatedCoder/CodoMetis.ValueRanges</RepositoryUrl>
<RepositoryType>git</RepositoryType>
</PropertyGroup>

<!--
Warnings are errors, with one carve-out.

GenerateDocumentationFile means CS1591 (missing XML comment) polices the public surface: the
.xml shipped in the package is what a consumer sees in IntelliSense, and a hole in it is a
hole in the API documentation. Making it an error is the only thing that keeps that true —
the sibling repository had accumulated 64 of them before doing this. Test projects opt out
of CS1591 in their own csproj; nothing else is exempt.

NU1901-NU1904 stay warnings. They report a vulnerable package, so whether the build passes
would depend on advisories published upstream rather than on anything in this commit; as
errors they would break unrelated CI runs at unpredictable moments. They must stay visible,
so they are exempted rather than suppressed with NoWarn.

Deliberate internal-API usage (EF1001) is acknowledged at the file, next to the reason,
never here — a repo-wide suppression would also hide the next accidental one.
-->
<PropertyGroup>
<WarningsNotAsErrors>NU1901;NU1902;NU1903;NU1904</WarningsNotAsErrors>
</PropertyGroup>

<!--
GeneratePackageOnBuild is deliberately NOT set. The SDK's pack targets prepend `Build` to
GenerateNuspecDependsOn only when NoBuild != true AND GeneratePackageOnBuild != true, so
turning it on silently makes plain `dotnet pack` behave as if the no-build switch had been
passed. That packs whatever happens to be in bin/ — stale output on a laptop, and NU5026 on
a clean checkout where bin/ is empty. The workflows always build first, which is why it
never bit here; PackagingConventionTests keeps it out.
-->

<!-- Provenance: a consumer stepping into this code gets the exact source it is running.
Source Link ships in the SDK, so no PackageReference is needed. -->
<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
// ReSharper disable once CheckNamespace — conventional namespace for options builder extensions,
// so UseValueRangesNodaTime is discoverable without an extra using.
namespace Microsoft.EntityFrameworkCore;
// EF1001 here is EF's analyzer reading CodoMetis.ValueRanges.EntityFrameworkCore.PostgreSQL.Internal
// as an internal namespace — it keys on the `EntityFrameworkCore.*.Internal` shape, not on an
// attribute. That warning is aimed at consumers of the plugin; this satellite is the same codebase
// and builds on those types by design.
#pragma warning disable EF1001


/// <summary>
/// CodoMetis.ValueRanges NodaTime extension method for <see cref="NpgsqlDbContextOptionsBuilder"/>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
using NpgsqlTypes;

namespace CodoMetis.ValueRanges.EntityFrameworkCore.PostgreSQL.NodaTime.Internal;
// EF1001 here is EF's analyzer reading CodoMetis.ValueRanges.EntityFrameworkCore.PostgreSQL.Internal
// as an internal namespace — it keys on the `EntityFrameworkCore.*.Internal` shape, not on an
// attribute. That warning is aimed at consumers of the plugin; this satellite is the same codebase
// and builds on those types by design.
#pragma warning disable EF1001


/// <summary>
/// Binds <see cref="YearMonthRange"/> to a month-aligned PostgreSQL <c>daterange</c>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
using NodaTime;

namespace CodoMetis.ValueRanges.EntityFrameworkCore.PostgreSQL.NodaTime.Internal;
// EF1001 here is EF's analyzer reading CodoMetis.ValueRanges.EntityFrameworkCore.PostgreSQL.Internal
// as an internal namespace — it keys on the `EntityFrameworkCore.*.Internal` shape, not on an
// attribute. That warning is aimed at consumers of the plugin; this satellite is the same codebase
// and builds on those types by design.
#pragma warning disable EF1001


/// <summary>
/// Binds <see cref="YearMonthSet"/> to a month-aligned PostgreSQL <c>date[]</c>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
using Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal;

namespace CodoMetis.ValueRanges.EntityFrameworkCore.PostgreSQL.Query;
// PgNewArrayExpression is Npgsql-internal (EF1001): building an array literal in the SQL tree has
// no public equivalent, and this translator only exists to build one. Acknowledged here, at the
// usage, rather than suppressed repo-wide.
#pragma warning disable EF1001


/// <summary>
/// Translates the value set algebra to PostgreSQL array operators, for every registered set
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,28 @@ public void ContinuousIntegrationBuild_IsSetOnlyUnderCi()
"ContinuousIntegrationBuild must be gated on the CI environment variable.");
}

/// <summary>
/// The SDK's pack targets prepend <c>Build</c> to <c>GenerateNuspecDependsOn</c> only when
/// <c>NoBuild != true</c> <em>and</em> <c>GeneratePackageOnBuild != true</c>, so setting the
/// latter silently makes plain <c>dotnet pack</c> behave as if <c>--no-build</c> had been
/// passed: it packs whatever is in <c>bin/</c> — stale output on a laptop, NU5026 on a clean
/// checkout. The workflows always build first, which is why it never bit here; this keeps it
/// from being reintroduced as a convenience.
/// </summary>
[TestMethod]
public void SharedBuildProperties_DoNotSetGeneratePackageOnBuild()
{
var all = XDocument.Load(Path.Combine(RepoLayout.Root.FullName, "Directory.Build.props"))
.Descendants("GeneratePackageOnBuild")
.ToList();

Assert.IsEmpty(
all,
"Directory.Build.props sets GeneratePackageOnBuild. That makes plain `dotnet pack` skip the "
+ "build and pack whatever is in bin/ — stale locally, NU5026 on a clean checkout. Build "
+ "first and pack with --no-build instead, as the workflows do.");
}

private static Dictionary<string, string> SharedBuildProperties()
{
var document = XDocument.Load(Path.Combine(RepoLayout.Root.FullName, "Directory.Build.props"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static async Task StartContainer(TestContext _)
{
try
{
_container = new PostgreSqlBuilder().WithImage("postgres:17-alpine").Build();
_container = new PostgreSqlBuilder("postgres:17-alpine").Build();
await _container.StartAsync();
ConnectionString = _container.GetConnectionString();

Expand Down