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
18 changes: 15 additions & 3 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
# https://github.com/dotnet/runtime/blob/main/.editorconfig

# https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-format
# dotnet format style --verify-no-changes --severity=info --verbosity=detailed
# Verify with: dotnet format style --verify-no-changes --severity=info --verbosity=detailed

# Root config
root = true

# Defaults: CRLF is the default, and only the LF exceptions below are declared.
# Most LF pins are shared with `.gitattributes`, which git enforces: `*.sh`, the husky pre-commit shebang, and Dockerfiles.
# Most LF pins are shared with `.gitattributes`, which git enforces: `*.sh`, the husky pre-commit shebang, `uv.lock`, and Dockerfiles.
# The workflow-YAML pin (`.github/workflows/*`) is `.editorconfig`-only.
# For that one, git stays passive (`* -text`) and CI (editorconfig-checker) enforces LF.
# Keep the `[*]` `end_of_line = crlf` default, which the Windows-GUI and WSL-engine workflow requires because Windows tooling misbehaves on LF.
Expand Down Expand Up @@ -45,6 +45,11 @@ indent_size = 2
[.github/workflows/*.{yml,yaml}]
end_of_line = lf

# Composite action metadata is Actions-owned like the workflows above, and Dependabot rewrites the
# `uses:` pins inside it with LF exactly as it does theirs, so declaring LF keeps it consistent.
[.github/actions/**/*.{yml,yaml}]
end_of_line = lf

# Linux scripts
[*.sh]
end_of_line = lf
Expand All @@ -55,12 +60,19 @@ end_of_line = lf
[.husky/pre-commit]
end_of_line = lf

# The uv tool regenerates uv.lock with LF on every platform, so pin it here.
# Without the pin an EOL check (editorconfig-checker or CI) fails on every `uv lock` or `uv sync` until the file is manually reconverted.
# The rationale matches the shebang and Dockerfile pins, where a tool owns the ending.
# A repo with no lockfile is unaffected, so this pin is forward-declared.
[uv.lock]
end_of_line = lf

# Dockerfiles are LF, because CRLF breaks RUN heredocs and line continuations.
[{Dockerfile,*.Dockerfile}]
end_of_line = lf

# .NET-only below, covering C# and ReSharper style.
# Everything above is the line-ending governance every derived repo carries.
# Everything above is the line-ending governance every derived repo carries, and a non-.NET repo may drop from here down.

# C# files
[*.cs]
Expand Down
18 changes: 15 additions & 3 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,24 @@
# Exception: scripts must stay LF regardless of the `* -text` default, because a CRLF shebang breaks execution.
# `.editorconfig` covers `*.sh`, but an extensionless executable matches no extension rule.
# Pin those here, so git enforces LF on checkout and on `--renormalize`.
# Any repo whose tooling ships extensionless scripts adds the matching path pin.
# The s6-overlay init is `Docker/s6-overlay/** text eol=lf`, and a husky or git hook is `.husky/pre-commit text eol=lf`.
# This repo ships no `.sh` script today, so the `*.sh` pin is forward-declared.
*.sh text eol=lf

# Husky.Net ships an extensionless pre-commit hook with a `/bin/sh` shebang, so pin it to LF.
# A CRLF shebang would break the hook's execution.
# Husky.Net ships an extensionless pre-commit hook with a `/bin/sh` shebang, which is the extensionless case the comment above names.
.husky/pre-commit text eol=lf

# Vanilla `.py` follows the CRLF default, since Python's universal newlines accept CRLF and it is commonly edited on Windows.
# Pin LF only for a `.py` executed directly via its shebang, by path.
# This repo carries no Python, so there is nothing to pin.
# Do not re-add a blanket `*.py text eol=lf`.

# The uv tool regenerates uv.lock with LF on every platform, so pin it here.
# That makes git enforce LF on checkout and renormalize, so a CRLF-default repo does not fight the tool on every `uv lock` or `uv sync`.
# A repo with no lockfile is unaffected, so this pin is forward-declared.
uv.lock text eol=lf

# Dockerfiles must be LF, because a CRLF breaks RUN heredocs and line continuations.
# This repo carries `Docker/Dockerfile` and no `*.Dockerfile`, so the second pin is forward-declared.
Dockerfile text eol=lf
*.Dockerfile text eol=lf
123 changes: 87 additions & 36 deletions .github/copilot-instructions.md

Large diffs are not rendered by default.

39 changes: 20 additions & 19 deletions .github/workflows/build-release-task.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,11 @@ jobs:
with:
ref: ${{ needs.get-version.outputs.GitCommitId }}

# Collect assets by the `release-asset-<branch>-*` pattern so this step is target-agnostic: subset releases by
# deleting the target, not `enable_*: false` (a skipped `needs` job would skip this release job too). The release
# step guards `fail_on_unmatched_files: true`, so at least one `release-asset-*` must match; a repo that drops
# every file-producing target (e.g. a Docker-only repo, whose release carries only source zip + README + LICENSE)
# relaxes that guard.
# Collect assets by the `release-asset-<branch>-*` pattern so this step is target-agnostic.
# Subset releases by deleting the target rather than by `enable_*: false`, since a skipped `needs` job would skip this release job too.
# The release step guards `fail_on_unmatched_files: true`, so at least one `release-asset-*` must match.
# A repo that drops every file-producing target relaxes that guard.
# A Docker-only repo is the case, its release carrying only the source zip + README + LICENSE.
- name: Download release asset artifacts step
if: ${{ inputs.expect_release_assets }}
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
Expand All @@ -156,8 +156,8 @@ jobs:
merge-multiple: true
path: ./Publish

# The weekly publisher re-runs even with no new commits, so the version may already be released. Skip the release
# step when a release for this tag already exists to avoid a no-op republish.
# The weekly publisher re-runs even with no new commits, so the version may already be released.
# Skip the release step when a release for this tag already exists, to avoid a no-op republish.
- name: Check for existing release step
id: release-exists
env:
Expand All @@ -179,10 +179,10 @@ jobs:
# `target_commitish` must be set explicitly: otherwise GitHub's REST API tags the release on the default branch.
# Pin it to `GitCommitId` so the tag is on the exact built commit, consistent with the SemVer2 tag and artifacts.
# Skip when the release already exists, but always let a manual `workflow_dispatch` through to refresh it.
# Every release (any branch, any target) is a tag on the built commit plus the auto-attached source zip, README,
# and LICENSE; targets amend it by uploading `release-asset-*` files (binaries/packages) or pushing elsewhere
# (image/registry). `fail_on_unmatched_files: true` fails loudly if a promised `release-asset-*` is missing or
# misnamed; a no-file-target repo relaxes it (see download step).
# Every release, on any branch and for any target, is a tag on the built commit plus the auto-attached source zip, README, and LICENSE.
# Targets amend it by uploading `release-asset-*` files (binaries/packages) or by pushing elsewhere (image/registry).
# `fail_on_unmatched_files: true` fails loudly if a promised `release-asset-*` is missing or misnamed.
# A no-file-target repo relaxes it (see download step).
- name: Create GitHub release step
if: ${{ steps.release-exists.outputs.exists == 'false' || github.event_name == 'workflow_dispatch' }}
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
Expand All @@ -197,16 +197,17 @@ jobs:
README.md
./Publish/*

# Surgical cleanup at the point of consumption: the release-asset-<branch>-* transfer artifacts now have durable
# copies on the release, so delete them by exact pattern to free the storage quota - scoped to this branch's
# assets, leaving diagnostics and any other artifacts. Gated to the same condition as the create step so it only
# deletes when a release was actually created/refreshed this run; on a skipped create (existing tag, no new
# commits) the fresh artifacts stay for the run, reaped by the retention-days: 1 backstop. Needs the caller to
# grant `actions: write` (publish-release's publish job does).
# Surgical cleanup at the point of consumption, since the release-asset-<branch>-* transfer artifacts now have durable copies on the release.
# Delete them by exact pattern to free the storage quota.
# The pattern is scoped to this branch's assets, leaving diagnostics and any other artifacts.
# It is gated to the same condition as the create step, so it only deletes when a release was actually created or refreshed this run.
# On a skipped create (an existing tag, no new commits) the fresh artifacts stay for the run, reaped by the retention-days: 1 backstop.
# It needs the caller to grant `actions: write`, which publish-release's publish job does.
- name: Delete consumed release asset artifacts step
if: ${{ inputs.expect_release_assets && (steps.release-exists.outputs.exists == 'false' || github.event_name == 'workflow_dispatch') }}
# Best-effort: the release is already published, so a listing/delete hiccup must never red the job; the
# retention-days: 1 backstop reaps anything missed. Deletes every matching id (a rerun can upload duplicates).
# Best-effort, since the release is already published, so a listing or delete hiccup must never red the job.
# The retention-days: 1 backstop reaps anything missed.
# It deletes every matching id, because a rerun can upload duplicates.
continue-on-error: true
env:
GH_TOKEN: ${{ github.token }}
Expand Down
4 changes: 2 additions & 2 deletions .markdownlint-cli2.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
// Prose paragraphs and data-heavy tables or URLs are intentionally long.
// Reflowing at 80 columns hurts readability and churns diffs.
"MD013": false,
// MD033 (inline HTML) stays enabled so native markdown wins.
// MD033 (inline HTML) stays enabled so native Markdown wins.
// HTML comments, used as reference-link dividers, pass it.
// The details and summary elements are allowed for GitHub collapsibles, which have no markdown equivalent.
// The details and summary elements are allowed for GitHub collapsibles, which have no Markdown equivalent.
// Every other element still flags.
"MD033": { "allowed_elements": ["details", "summary"] },
// Require fenced code blocks over the legacy 4-space-indented style.
Expand Down
Loading
Loading