Skip to content

chore: update the build infrastructure and adopt the latest shared agent instructions - #22

Merged
xperiandri merged 19 commits into
mainfrom
chore/infrastructure
Oct 10, 2026
Merged

xperiandri merged 19 commits into
mainfrom
chore/infrastructure

Conversation

@xperiandri

@xperiandri xperiandri commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator

Proposed Changes

Brings the repository infrastructure up to date; the library code changes only by a whitespace reformat with Fantomas 8.0.5. The build restores the local tools once before every restore, formats each project once per build and collects coverage with the MSTest runner (dotnet test --project … --coverage) – the AltCover properties it passed before did nothing, so ENABLE_COVERAGE produced no coverage. The package is described as F# bindings for System.Collections.Immutable again instead of an Azure Cosmos DB API, and the assembly gets version 1.0.0.0 instead of 0.0.0.0 because the generated AssemblyInfo.fs is now compiled. FAKE is updated to 6.1.5: 6.1.4 dropped the date of the last entry of CHANGELOG.md, which is the only one here, and GenerateAssemblyInfo failed on it, which stopped PublishToGitHub; the target now also writes ReleaseDate only for an entry that has a date. Agents get the F# MCP server, the Claude Code configuration (CLAUDE.md, AGENTS.md, mcpServers), the latest shared coding instructions and a path-scoped rule for TestCategories.fs.

Types of changes

What types of changes does your code introduce to FSharp.Collections.Immutable?
Put an x in the boxes that apply

  • Bugfix (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)

Checklist

Put an x in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.

  • Build and tests pass locally – build.cmd with CI=true and ENABLE_COVERAGE=true in Debug and Release, plus GenerateCoverageReport and BuildDocs
  • I have added tests that prove my fix is effective or that my feature works (if appropriate) – no tests were added, the library behaves as before
  • I have added necessary documentation (if appropriate) – README.md and .github/copilot-instructions.md

Further comments

  • CheckFormatCode starts to check. On CI it ran before any tool was restored, found no Fantomas and passed whatever the formatting was.
  • The local tools are restored by one instance of Directory.Build.targets per build. Restoring them in every project made the projects of a solution run dotnet tool restore at the same time, and the Restore dependencies step of the Copilot setup failed on Linux.
  • Format runs Fantomas twice on purpose: one pass is not always idempotent.
  • The package now carries the PDB inside the .nupkg; the .snupkg is still produced.
  • The library and the tests keep targeting net8.0, so the workflows and the dev container keep installing the 8.x runtime next to the SDK 10.0.401.
  • PublishToGitHub and the documentation deployment run on main only. Locally the build was run with the prerelease AssemblyInfo.fs that PublishToGitHub generates (1.0.1-ci): it compiles with the FS2003 warning about a version that is not numeric.
  • The coverage report is empty for now: the tests are placeholders that do not call the library.
  • The commits are small and build one by one, so a rebase or a merge commit keeps them readable.

🤖 Generated with Claude Code

xperiandri and others added 17 commits October 10, 2026 23:21
Update `Microsoft.SourceLink.GitHub` to `10.0.401` together with the SDK it ships with.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nfig

Batch files are checked out with CRLF and PowerShell scripts with LF on every platform,
and `.editorconfig` states the same instead of asking for CRLF in PowerShell scripts.

The inline comments of `.editorconfig` move onto their own lines:
the specification does not support inline comments, so they were read as part of the value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`.editorconfig` follows the settings of Fantomas 8:

- `fsharp_keep_indent_in_branch` became `fsharp_experimental_keep_indent_in_branch`;
  under its old name the setting was ignored.
- `fsharp_semicolon_at_end_of_line` and `fsharp_max_dot_get_expression_width` no longer exist.
- `end_of_line=lf` matches the line endings `.gitattributes` stores F# files with,
  so formatting on Windows no longer rewrites them as CRLF.

The comments state the current defaults and link to the current documentation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fantomas 8 no longer puts a space between a type application and its argument list:
`Create<'T> ()` becomes `Create<'T>()`. Whitespace only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`ToolRestore` ran only in design-time builds, so a command-line build relied on the FAKE
`DotnetToolRestore` target, and that target was a dependency of `BuildDocs` alone:
on CI `CheckFormatCode` found no Fantomas and passed without checking anything.
`ToolRestore` now runs before every restore, and the FAKE target is gone.

`ToolUpdate` is removed: its `Outputs` used an undefined property, so MSBuild always skipped it.

Formatting is delegated to one instance of a project without a target framework,
so a project is formatted once per build however many target frameworks it has,
and Fantomas runs twice because one pass is not always idempotent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tCover leftovers

`DotnetTest` passed `/p:AltCover*` properties although no project references AltCover,
and `GenerateCoverageReport` looked for `tests/**/coverage*.xml`, which nothing produced,
so `ENABLE_COVERAGE` collected no coverage.

`DotnetTest` now runs `dotnet test --project` for each test project and lets the MSTest runner
collect coverage with `--coverage --coverage-output-format cobertura` into `TestResults`,
where `GenerateCoverageReport` reads it and writes HTML and Cobertura reports.
Coverage is collected when `ENABLE_COVERAGE` is set or `GenerateCoverageReport` is among the targets.

Also:

- the release commit is named `release: bump version to ...`;
- `quoted` is shared by the test and the documentation targets;
- the workflows no longer explain `ENABLE_COVERAGE: false` with AltCover.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`src/Directory.Build.props` holds what every library project shares, next to the
`tests/Directory.Build.props` the test projects already have: it marks the project as packable,
generates the documentation file, publishes the repository URL, embeds untracked sources
and puts the PDB into the package next to the assembly.

The solution groups the projects into `src` and `tests` folders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y has no date

`GenerateAssemblyInfo` read `latestEntry.Date.Value` and failed with a `NullReferenceException`
for an entry without a date. The `ReleaseDate` metadata is now written only when the entry has one.

This is the case in this repository today: FAKE `6.1.4` moves the link references out of the last
entry of the changelog and rebuilds that entry from its versions and changes alone, dropping its
date and description (fixed in FAKE after `6.1.4`, not released yet). `1.0.0` is the only entry,
so it is both the latest and the last one, and `PublishToGitHub`, which generates the assembly info,
could not get past this target.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ersion

The package described itself as an F# API for Azure Cosmos DB and carried the
`AzureCosmosDisableNewtonsoftJsonCheck` property, both left over from the project file
this one was copied from. The description is `F# bindings for System.Collections.Immutable` again.

`GenerateAssemblyInfo` is switched off for the SDK because the FAKE target of the same name
writes `AssemblyInfo.fs`, but the project did not compile that file,
so the assembly had version `0.0.0.0`. The generated file is now the first compiled file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FsLangMCP gives agents semantic F# tools: symbol lookup, diagnostics, usages and refactoring previews.
It is a local tool pinned in the tool manifest, so `dotnet tool restore` installs it,
and `.mcp.json` starts it with `dotnet tool run fslangmcp`.

The servers in `.mcp.json` are sorted by name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- `CLAUDE.md` imports `.github/copilot-instructions.md`, so GitHub Copilot and Claude Code share one
  set of instructions; `AGENTS.md` points other agents at the same file.
- `.mcp.json` lists the servers for Claude Code under `mcpServers` next to `servers`.
- The GitHub MCP server does not support the OAuth dynamic client registration Claude Code needs,
  so `.claude/scripts/github-mcp-headers.ps1` passes it the token Git Credential Manager already stores.
- `ClaudeSkillsLink` links `.claude/skills` to `.github/skills` when that folder exists;
  the link is local and git-ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The generic sections are replaced with the current shared ones:

- `MCP Servers` – when to prefer the F#, GitHub and Microsoft Docs servers;
- `F# Coding Guidelines` – tooling, asynchrony and cancellation, values and collections
  (`voption`, struct tuples, `ToLookup`, pipelines kept in one module, comparing `System.Type` values),
  functions, lambdas and strings (explicit `StringComparison`, spans), nullable reference types,
  XML documentation comments and the order of `open` statements;
- `Naming Conventions` – test names with spaces;
- `Testing` – `StringAssert`, `Assert.Contains`, `Assert.HasCount` and running tests with `--no-build`.

The project details, the solution structure, the libraries in use and the test category rules
are specific to this repository and stay as they are.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`TestCategories.fs` keeps its `TestCategoryBaseAttribute` descendants sorted by type name.
The rule lives in `.github/instructions/test-categories.instructions.md`, which GitHub Copilot applies
to that file, and `.claude/rules/test-categories.md` imports it for Claude Code under the same path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- `actions/configure-pages` `v5` -> `v6`
- `actions/upload-pages-artifact` `v4` -> `v5`
- `actions/deploy-pages` `v4` -> `v5`

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The dev container installs the starship feature and enables it in zsh when the container is created.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e its sibling keys

`target` was indented by five spaces while the other safe outputs indent their keys by four.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README:

- the required SDK is the `10.0.401` pinned in `global.json`, not `8.0 or higher`;
- `CONFIGURATION` defaults to `Debug`, and to `Release` only when `PublishToNuGet` runs;
- `ENABLE_COVERAGE` and `DotnetTest` describe the MSTest runner instead of AltCover and the solution file;
- `PublishToNuGet` pushes with `dotnet nuget push`, not `paket push`;
- the release commit is named ``release: bump version to `x.y.z` ``;
- the badge of the `.NET Core` workflow, which does not exist, is removed,
  and the NuGet badge is loaded over HTTPS.

The pull request template names this project instead of the one it was copied from.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 10, 2026 22:44

Copilot AI commented Oct 10, 2026

Copy link
Copy Markdown

One or more custom setup steps configured for this repository failed during this Copilot code review run:

Restore dependencies

Setup steps run before each review. If the review above is missing context, or no review was posted at all, the failing step above may be the cause. See the workflow run for failure details, fix your setup steps configuration, and re-request a review.

Note

You can configure setup steps for Copilot code review separately from Copilot cloud agent with a copilot-code-review.yml file. Read the docs for details.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The formatting target currently executes Fantomas twice for every format pass.

1 open finding
What changed in this PR

Modernizes build, release, coverage, formatting, and agent infrastructure while preserving library behavior.

Changes:

  • Updates .NET, Fantomas, SourceLink, GitHub Actions, and coverage tooling.
  • Corrects package and assembly metadata generation.
  • Adds shared agent/MCP configuration and applies formatting updates.
File Description
src/​FSharp.Collections.Immutable/​Stack.fs Applies Fantomas formatting.
src/​FSharp.Collections.Immutable/​Sets.fs Applies Fantomas formatting.
src/​FSharp.Collections.Immutable/​Queue.fs Applies Fantomas formatting.
src/​FSharp.Collections.Immutable/​Maps.fs Applies Fantomas formatting.
src/​FSharp.Collections.Immutable/​ImmutableList.fs Applies Fantomas formatting.
src/​FSharp.Collections.Immutable/​FSharp.Collections.Immutable.fsproj Corrects package metadata and compiles assembly metadata.
src/​FSharp.Collections.Immutable/​FlatList.fs Applies Fantomas formatting.
src/​FSharp.Collections.Immutable/​AssemblyInfo.fs Adds generated version and assembly metadata.
src/​Directory.Build.props Configures library packaging and PDB inclusion.
README.md Updates build, coverage, and release documentation.
global.json Pins .NET SDK 10.0.401.
FSharp.Collections.Immutable.slnx Organizes projects into solution folders.
Directory.Packages.props Updates SourceLink.
Directory.Build.targets Revises tool restoration, formatting, and skill linking.
CLAUDE.md Redirects Claude Code to shared instructions.
build/​Changelog.fs Applies formatting.
build/​build.fs Migrates coverage and improves release metadata handling.
AGENTS.md Directs agents to shared repository instructions.
.mcp.json Configures F#, GitHub, and Microsoft Docs MCP servers.
.gitignore Ignores the generated Claude skills link.
.github/​workflows/​repo-assist.md Corrects formatting.
.github/​workflows/​publish_release.yml Removes obsolete AltCover commentary.
.github/​workflows/​publish_ci.yml Removes obsolete AltCover commentary.
.github/​workflows/​fsdocs-gh-pages.yml Updates GitHub Pages actions.
.github/​PULL_REQUEST_TEMPLATE.md Corrects the project name.
.github/​instructions/​test-categories.instructions.md Adds scoped test-category guidance.
.github/​copilot-instructions.md Expands shared coding and tooling guidance.
.gitattributes Defines platform-appropriate script line endings.
.editorconfig Updates Fantomas 8 and line-ending configuration.
.devcontainer/​devcontainer.json Adds and initializes Starship.
.config/​dotnet-tools.json Adds FsLangMCP and updates Fantomas.
.claude/​scripts/​github-mcp-headers.ps1 Supplies GitHub MCP authentication headers.
.claude/​rules/​test-categories.md Bridges Claude to scoped test guidance.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread Directory.Build.targets
xperiandri and others added 2 commits October 11, 2026 00:49
FAKE `6.1.5` keeps the date and the description of the last entry of the changelog, which `6.1.4` dropped.
`1.0.0` is the only entry here, so:

- the regenerated `AssemblyInfo.fs` now carries the `ReleaseDate` metadata;
- the release notes of the package start with `## [1.0.0] - 2020-02-23` and `First release`
  instead of a bare `## [1.0.0]`.

`GenerateAssemblyInfo` still writes `ReleaseDate` only for an entry that has a date, because the date
is optional in a changelog entry; its comment no longer refers to the FAKE defect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A solution restores its projects in parallel, so `ToolRestore` ran `dotnet tool restore` in every project
at the same time and all of them touched the same marker file. The `Restore dependencies` step of
the Copilot setup, which restores the solution, failed on Linux after `ToolRestore` started to run
on every restore.

Every project now delegates to one instance of `Directory.Build.targets`, which MSBuild builds once per build,
so the tools are restored once and the other projects wait for that run.
The Copilot setup no longer restores the tools on its own before restoring the solution.

`Format` says why it runs Fantomas twice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@xperiandri
xperiandri merged commit 14d01ef into main Oct 10, 2026
9 checks passed
@xperiandri
xperiandri deleted the chore/infrastructure branch October 10, 2026 23:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants