Skip to content

Release 2.8.0#2329

Merged
mjcheetham merged 86 commits intoreleasefrom
main
Apr 28, 2026
Merged

Release 2.8.0#2329
mjcheetham merged 86 commits intoreleasefrom
main

Conversation

@mjcheetham
Copy link
Copy Markdown
Contributor

Changes:

dependabot Bot and others added 30 commits January 14, 2026 20:32
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 5.0.1 to 5.1.0.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](actions/setup-dotnet@v5.0.1...v5.1.0)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-version: 5.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Context:
Git configuration queries currently spawn a new git process for each
TryGet(), GetAll(), or Enumerate() call. In scenarios where multiple
config values are needed (e.g., credential helper initialization), this
results in dozens of git process spawns, each parsing the same config
files repeatedly. This impacts performance, especially on Windows where
process creation is more expensive.

Justification:
Rather than caching individual queries, we cache the entire config
output from a single 'git config list --show-origin -z' call. This
approach provides several benefits:
- Single process spawn loads all config values at once
- Origin information allows accurate level filtering (system/global/local)
- Cache invalidation on write operations keeps data consistent
- Thread-safe implementation supports concurrent access

We only cache Raw type queries since Bool and Path types require Git's
canonicalization logic. Cache is loaded lazily on first access and
invalidated on any write operation (Set, Add, Unset, etc.).

Implementation:
Added ConfigCacheEntry class to store origin, value, and level for each
config entry. The ConfigCache class parses the NUL-delimited output from
'git config list --show-origin -z' (format: origin\0key\nvalue\0) and
stores entries in a case-insensitive dictionary keyed by config name.

Level detection examines the file path in the origin to determine
System/Global/Local classification. Fallback to individual git config
commands occurs if cache load fails or for typed (Bool/Path) queries.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Context:
The caching implementation needed comprehensive tests to verify correct
behavior across different scenarios: cache hits, cache invalidation,
level filtering, and multivar handling. Tests revealed a critical bug
where the cache returned the wrong value when multiple config levels
(system/global/local) defined the same key.

Justification:
Tests follow existing patterns in GitConfigurationTests.cs, creating
temporary repositories and verifying cache behavior through the public
IGitConfiguration interface rather than testing internal cache classes
directly. This ensures we test the actual behavior users will experience.

The precedence bug occurred because ConfigCache.TryGet() returned the
first matching entry when it should return the last one. Git outputs
config values in precedence order (system, global, local), with later
values overriding earlier ones. Returning the last match correctly
implements Git's precedence rules.

Implementation:
Added 8 new test methods covering:
- Cache loading and retrieval (TryGet, GetAll, Enumerate)
- Cache invalidation on write operations (Set, Add, Unset)
- Level filtering to isolate local/global/system values
- Typed queries that bypass cache for Git's canonicalization

Fixed ConfigCache.TryGet() to iterate through all matching entries and
return the last one instead of the first, ensuring local config wins
over global, which wins over system.

All 805 tests pass with the fix applied.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
[`install-from-source.sh`](https://github.com/git-ecosystem/git-credential-manager/blob/v2.7.2/src/linux/Packaging.Linux/install-from-source.sh#L234)
already allows you to install on `mariner`. But `mariner` is now
`azurelinux`, so we ought to allow both.

The installer works fine without any other modifications. And I have had
no issues using gcm on azurelinux3 so far.

I also add azurelinux3 to the test matrix.
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet)
from 5.0.1 to 5.1.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-dotnet/releases">actions/setup-dotnet's
releases</a>.</em></p>
<blockquote>
<h2>v5.1.0</h2>
<h2>What's Changed</h2>
<h3>Documentation</h3>
<ul>
<li>Readme update for environment variable on self hosted linux runners
by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-dotnet/pull/689">actions/setup-dotnet#689</a></li>
<li>Contributor icon updates by <a
href="https://github.com/Falco20019"><code>@​Falco20019</code></a> in <a
href="https://redirect.github.com/actions/setup-dotnet/pull/604">actions/setup-dotnet#604</a></li>
</ul>
<h3>Dependency updates</h3>
<ul>
<li>Upgrade actions/checkout from 5 to 6 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/setup-dotnet/pull/684">actions/setup-dotnet#684</a></li>
<li>Upgrade to latest actions packages by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/setup-dotnet/pull/687">actions/setup-dotnet#687</a></li>
<li>Upgrade dependencies in testproject and checkout in Readme by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-dotnet/pull/692">actions/setup-dotnet#692</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-dotnet/pull/689">actions/setup-dotnet#689</a></li>
<li><a
href="https://github.com/Falco20019"><code>@​Falco20019</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-dotnet/pull/604">actions/setup-dotnet#604</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-dotnet/compare/v5...v5.1.0">https://github.com/actions/setup-dotnet/compare/v5...v5.1.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/setup-dotnet/commit/baa11fbfe1d6520db94683bd5c7a3818018e4309"><code>baa11fb</code></a>
Bump test dependencies to resolve System.Net.Http vulnerability, update
workf...</li>
<li><a
href="https://github.com/actions/setup-dotnet/commit/24ec4f204bea672fb937f8f9f3bfec35ba0dc7b5"><code>24ec4f2</code></a>
Upgrade to latest actions packages (<a
href="https://redirect.github.com/actions/setup-dotnet/issues/687">#687</a>)</li>
<li><a
href="https://github.com/actions/setup-dotnet/commit/4c100cb5e4b37e8b502c0ca5acbab36ee401b85f"><code>4c100cb</code></a>
Fix icons (<a
href="https://redirect.github.com/actions/setup-dotnet/issues/604">#604</a>)</li>
<li><a
href="https://github.com/actions/setup-dotnet/commit/25328d894dc34d01d191df4849cb7f5402e3f142"><code>25328d8</code></a>
Bump actions/checkout from 5 to 6 (<a
href="https://redirect.github.com/actions/setup-dotnet/issues/684">#684</a>)</li>
<li><a
href="https://github.com/actions/setup-dotnet/commit/937b8dd3814c642a65e599b368dfac491d9c83da"><code>937b8dd</code></a>
Update README with note on setting DOTNET_INSTALL_DIR for Linux
permission is...</li>
<li>See full diff in <a
href="https://github.com/actions/setup-dotnet/compare/v5.0.1...v5.1.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/setup-dotnet&package-manager=github_actions&previous-version=5.0.1&new-version=5.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

You can trigger a rebase of this PR by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

> **Note**
> Automatic rebases have been disabled on this pull request as it has
been open for over 30 days.
Bumps [lycheeverse/lychee-action](https://github.com/lycheeverse/lychee-action) from 2.7.0 to 2.8.0.
- [Release notes](https://github.com/lycheeverse/lychee-action/releases)
- [Commits](lycheeverse/lychee-action@a8c4c7c...8646ba3)

---
updated-dependencies:
- dependency-name: lycheeverse/lychee-action
  dependency-version: 2.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps
[actions/upload-artifact](https://github.com/actions/upload-artifact)
from 6 to 7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/upload-artifact/releases">actions/upload-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>v7 What's new</h2>
<h3>Direct Uploads</h3>
<p>Adds support for uploading single files directly (unzipped). Callers
can set the new <code>archive</code> parameter to <code>false</code> to
skip zipping the file during upload. Right now, we only support single
files. The action will fail if the glob passed resolves to multiple
files. The <code>name</code> parameter is also ignored with this
setting. Instead, the name of the artifact will be the name of the
uploaded file.</p>
<h3>ESM</h3>
<p>To support new versions of the <code>@actions/*</code> packages,
we've upgraded the package to ESM.</p>
<h2>What's Changed</h2>
<ul>
<li>Add proxy integration test by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/upload-artifact/pull/754">actions/upload-artifact#754</a></li>
<li>Upgrade the module to ESM and bump dependencies by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/762">actions/upload-artifact#762</a></li>
<li>Support direct file uploads by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/764">actions/upload-artifact#764</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Link"><code>@​Link</code></a>- made
their first contribution in <a
href="https://redirect.github.com/actions/upload-artifact/pull/754">actions/upload-artifact#754</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v6...v7.0.0">https://github.com/actions/upload-artifact/compare/v6...v7.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/upload-artifact/commit/bbbca2ddaa5d8feaa63e36b76fdaad77386f024f"><code>bbbca2d</code></a>
Support direct file uploads (<a
href="https://redirect.github.com/actions/upload-artifact/issues/764">#764</a>)</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/589182c5a4cec8920b8c1bce3e2fab1c97a02296"><code>589182c</code></a>
Upgrade the module to ESM and bump dependencies (<a
href="https://redirect.github.com/actions/upload-artifact/issues/762">#762</a>)</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/47309c993abb98030a35d55ef7ff34b7fa1074b5"><code>47309c9</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/754">#754</a>
from actions/Link-/add-proxy-integration-tests</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/02a8460834e70dab0ce194c64360c59dc1475ef0"><code>02a8460</code></a>
Add proxy integration test</li>
<li>See full diff in <a
href="https://github.com/actions/upload-artifact/compare/v6...v7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-artifact&package-manager=github_actions&previous-version=6&new-version=7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
Bumps
[lycheeverse/lychee-action](https://github.com/lycheeverse/lychee-action)
from 2.7.0 to 2.8.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/lycheeverse/lychee-action/releases">lycheeverse/lychee-action's
releases</a>.</em></p>
<blockquote>
<h2>v2.8.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update lycheeVersion to v0.23.0 by <a
href="https://github.com/github-actions"><code>@​github-actions</code></a>[bot]
in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/324">lycheeverse/lychee-action#324</a></li>
<li>Update args for lychee-action to use root-dir by <a
href="https://github.com/mre"><code>@​mre</code></a> in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/314">lycheeverse/lychee-action#314</a></li>
<li>Update test to use <code>--root-dir</code> instead of the deprecated
<code>--base</code> by <a
href="https://github.com/mre"><code>@​mre</code></a> in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/315">lycheeverse/lychee-action#315</a></li>
<li>Bump actions/checkout from 5 to 6 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/316">lycheeverse/lychee-action#316</a></li>
<li>Bump actions/cache from 4 to 5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/319">lycheeverse/lychee-action#319</a></li>
<li>Bump peter-evans/create-pull-request from 7 to 8 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/318">lycheeverse/lychee-action#318</a></li>
<li>Add message with Summary report URL by <a
href="https://github.com/atteggiani"><code>@​atteggiani</code></a> in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/326">lycheeverse/lychee-action#326</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/atteggiani"><code>@​atteggiani</code></a> made
their first contribution in <a
href="https://redirect.github.com/lycheeverse/lychee-action/pull/326">lycheeverse/lychee-action#326</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/lycheeverse/lychee-action/compare/v2.7.0...v2.8.0">https://github.com/lycheeverse/lychee-action/compare/v2.7.0...v2.8.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/lycheeverse/lychee-action/commit/8646ba30535128ac92d33dfc9133794bfdd9b411"><code>8646ba3</code></a>
Add message with Summary report URL (<a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/326">#326</a>)</li>
<li><a
href="https://github.com/lycheeverse/lychee-action/commit/c6e7911b99c9aec72bbd07b92c99d2c76417e260"><code>c6e7911</code></a>
[create-pull-request] automated change</li>
<li><a
href="https://github.com/lycheeverse/lychee-action/commit/631725aa742da9b8eb5e3541942ab992832223e3"><code>631725a</code></a>
Bump peter-evans/create-pull-request from 7 to 8 (<a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/318">#318</a>)</li>
<li><a
href="https://github.com/lycheeverse/lychee-action/commit/942f324b8945333d3fb5ce5f27a35d126ffdf47a"><code>942f324</code></a>
Bump actions/cache from 4 to 5 (<a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/319">#319</a>)</li>
<li><a
href="https://github.com/lycheeverse/lychee-action/commit/79de8811d696d79a713d425d265c9870b929fbf2"><code>79de881</code></a>
Bump actions/checkout from 5 to 6 (<a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/316">#316</a>)</li>
<li><a
href="https://github.com/lycheeverse/lychee-action/commit/1ef33e2493308e49729a7789ddd73e7f8bed8f45"><code>1ef33e2</code></a>
Update test to use <code>--root-dir</code> instead of the deprecated
<code>--base</code> (<a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/315">#315</a>)</li>
<li><a
href="https://github.com/lycheeverse/lychee-action/commit/50a631ed9f6d8c011c89939867250faa2fc95752"><code>50a631e</code></a>
Update args for lychee-action to use root-dir (<a
href="https://redirect.github.com/lycheeverse/lychee-action/issues/314">#314</a>)</li>
<li>See full diff in <a
href="https://github.com/lycheeverse/lychee-action/compare/a8c4c7cb88f0c7386610c35eb25108e448569cb0...8646ba30535128ac92d33dfc9133794bfdd9b411">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=lycheeverse/lychee-action&package-manager=github_actions&previous-version=2.7.0&new-version=2.8.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
…2263)

Co-authored-by: marekzmyslowski <1062877+marekzmyslowski@users.noreply.github.com>
…teFiles

Co-authored-by: marekzmyslowski <1062877+marekzmyslowski@users.noreply.github.com>
Co-authored-by: marekzmyslowski <1062877+marekzmyslowski@users.noreply.github.com>
… in GetGpgId

Co-authored-by: marekzmyslowski <1062877+marekzmyslowski@users.noreply.github.com>
…behaviour

Co-authored-by: marekzmyslowski <1062877+marekzmyslowski@users.noreply.github.com>
…asswords

Co-authored-by: marekzmyslowski <1062877+marekzmyslowski@users.noreply.github.com>
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 5.1.0 to 5.2.0.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](actions/setup-dotnet@v5.1.0...v5.2.0)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-version: 5.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Clarified registry access for 32-bit GCM on 64-bit Windows.
Clarified registry access for 32-bit GCM on 64-bit Windows since we now
have native x64 and ARM64 builds for Windows.
Context:
The config cache only stored raw (untyped) values, so Bool and Path
queries always fell back to spawning individual git processes. Since
Git's --type flag canonicalizes values (e.g., expanding ~/... for
paths, normalizing yes/on/1 to true for bools), serving these from
the raw cache would return incorrect values.

Justification:
Instead of bypassing the cache for typed queries, we maintain a
separate cache per GitConfigurationType. Each cache is loaded with
the appropriate --type flag passed to 'git config list', so Git
performs canonicalization during the bulk load. This preserves the
correctness guarantee while extending the performance benefit to
all query types.

The cache result is now authoritative when loaded: if a key is not
found in the cache, we return 'not found' directly rather than
falling back to an individual git process call. This avoids a
redundant process spawn when the key genuinely doesn't exist.

Implementation:
Changed _cache from a single ConfigCache to a Dictionary keyed by
GitConfigurationType. EnsureCacheLoaded() now accepts a type
parameter and passes --no-type, --type=bool, or --type=path to the
git config list command. InvalidateCache() clears all type-specific
caches on any write operation.

Renamed TypedQuery_DoesNotUseCache test to
TypedQuery_CanonicalizesValues since typed queries now use their
own type-specific cache rather than bypassing the cache entirely.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Context:
The config cache uses 'git config list --type=<X>' to load
type-specific caches (raw, bool, path). The --type flag for the
'list' subcommand requires a fix queued for the Git 2.54.0
release. On Git 2.53 and earlier, the command succeeds but
silently ignores the --type parameter, returning raw values
instead of canonicalized ones. This means bool caches would
contain 'yes'/'on' instead of 'true', and path caches would
contain unexpanded '~/...' instead of absolute paths.

Justification:
Because the command exits 0 on older Git, the cache appears to
load successfully and the fallback paths never trigger. This makes
the bug silent and data-dependent: lookups work for values that
happen to already be in canonical form but return wrong results
for others. A version gate is the only reliable way to avoid this.

The check is in the constructor body rather than the constructor
chain so we can log a trace message when caching is disabled. The
explicit useCache parameter is preserved for tests that need to
control caching behavior independently of version.

Implementation:
Added ConfigListTypeMinVersion constant (2.54.0) and a version
comparison in the GitProcessConfiguration constructor. When
useCache is requested but git.Version is below the minimum, the
constructor overrides useCache to false and emits a trace line.
All existing fallback paths continue to work unchanged for users
on older Git, who will benefit from the cache automatically once
they upgrade.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The error in full:

    error CS0121: The call is ambiguous between the following methods or properties: 'string.Split(char[]?, StringSplitOptions)' and 'string.Split(string?, StringSplitOptions)' [src/shared/Core/Core.csproj::TargetFramework=net8.0]

Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
Co-authored-by: mjcheetham <5658207+mjcheetham@users.noreply.github.com>
…2287)

The error in full:

error CS0121: The call is ambiguous between the following methods or
properties: 'string.Split(char[]?, StringSplitOptions)' and
'string.Split(string?, StringSplitOptions)'
[src/shared/Core/Core.csproj::TargetFramework=net8.0]
Context:
The config cache path already gates on Git 2.54.0+ (or microsoft/git
2.53.0.vfs.0.1+) to use 'git config list --type=<X>'. These versions
also support --show-scope, which directly reports the scope (system,
global, local) as a simple string rather than a file path.

Justification:
The --show-origin approach required heuristic path matching to guess
the scope from origin paths like 'file:/etc/gitconfig' or
'file:~/.gitconfig'. This was fragile: it could fail on non-standard
install prefixes or platform-specific paths (e.g., Windows). Since
--show-scope is available at the same Git versions we already require,
we can use it for reliable scope detection with no guesswork.

Implementation:
- Replace --show-origin with --show-scope in the git config list call
- Replace DetermineLevel() path heuristic with ParseScope() that does
  a direct string match on 'system', 'global', 'local'
- Remove the now-unused Origin property from ConfigCacheEntry
- Rename origin variables to scope throughout ConfigCache.Load()

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI and others added 21 commits April 23, 2026 08:40
Bumps [actions/github-script](https://github.com/actions/github-script)
from 8 to 9.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/github-script/releases">actions/github-script's
releases</a>.</em></p>
<blockquote>
<h2>v9.0.0</h2>
<p><strong>New features:</strong></p>
<ul>
<li><strong><code>getOctokit</code> factory function</strong> —
Available directly in the script context. Create additional
authenticated Octokit clients with different tokens for multi-token
workflows, GitHub App tokens, and cross-org access. See <a
href="https://github.com/actions/github-script#creating-additional-clients-with-getoctokit">Creating
additional clients with <code>getOctokit</code></a> for details and
examples.</li>
<li><strong>Orchestration ID in user-agent</strong> — The
<code>ACTIONS_ORCHESTRATION_ID</code> environment variable is
automatically appended to the user-agent string for request
tracing.</li>
</ul>
<p><strong>Breaking changes:</strong></p>
<ul>
<li><strong><code>require('@actions/github')</code> no longer works in
scripts.</strong> The upgrade to <code>@actions/github</code> v9
(ESM-only) means <code>require('@actions/github')</code> will fail at
runtime. If you previously used patterns like <code>const { getOctokit }
= require('@actions/github')</code> to create secondary clients, use the
new injected <code>getOctokit</code> function instead — it's available
directly in the script context with no imports needed.</li>
<li><code>getOctokit</code> is now an injected function parameter.
Scripts that declare <code>const getOctokit = ...</code> or <code>let
getOctokit = ...</code> will get a <code>SyntaxError</code> because
JavaScript does not allow <code>const</code>/<code>let</code>
redeclaration of function parameters. Use the injected
<code>getOctokit</code> directly, or use <code>var getOctokit =
...</code> if you need to redeclare it.</li>
<li>If your script accesses other <code>@actions/github</code> internals
beyond the standard <code>github</code>/<code>octokit</code> client, you
may need to update those references for v9 compatibility.</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Add ACTIONS_ORCHESTRATION_ID to user-agent string by <a
href="https://github.com/Copilot"><code>@​Copilot</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/695">actions/github-script#695</a></li>
<li>ci: use deployment: false for integration test environments by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/712">actions/github-script#712</a></li>
<li>feat!: add getOctokit to script context, upgrade
<code>@​actions/github</code> v9, <code>@​octokit/core</code> v7, and
related packages by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/700">actions/github-script#700</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Copilot"><code>@​Copilot</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/695">actions/github-script#695</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/github-script/compare/v8.0.0...v9.0.0">https://github.com/actions/github-script/compare/v8.0.0...v9.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/github-script/commit/3a2844b7e9c422d3c10d287c895573f7108da1b3"><code>3a2844b</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/github-script/issues/700">#700</a>
from actions/salmanmkc/expose-getoctokit + prepare re...</li>
<li><a
href="https://github.com/actions/github-script/commit/ca10bbdd1a7739de09e99a200c7a59f5d73a4079"><code>ca10bbd</code></a>
fix: use <code>@​octokit/core/</code>types import for v7
compatibility</li>
<li><a
href="https://github.com/actions/github-script/commit/86e48e20ac85c970ed1f96e718fd068173948b7b"><code>86e48e2</code></a>
merge: incorporate main branch changes</li>
<li><a
href="https://github.com/actions/github-script/commit/c1084728b5b935ec4ddc1e4cee877b01797b3ff9"><code>c108472</code></a>
chore: rebuild dist for v9 upgrade and getOctokit factory</li>
<li><a
href="https://github.com/actions/github-script/commit/afff112e4f8b57c718168af75b89ce00bc8d091d"><code>afff112</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/github-script/issues/712">#712</a>
from actions/salmanmkc/deployment-false + fix user-ag...</li>
<li><a
href="https://github.com/actions/github-script/commit/ff8117e5b78c415f814f39ad6998f424fee7b817"><code>ff8117e</code></a>
ci: fix user-agent test to handle orchestration ID</li>
<li><a
href="https://github.com/actions/github-script/commit/81c6b7876079abe10ff715951c9fc7b3e1ab389d"><code>81c6b78</code></a>
ci: use deployment: false to suppress deployment noise from integration
tests</li>
<li><a
href="https://github.com/actions/github-script/commit/3953caf8858d318f37b6cc53a9f5708859b5a7b7"><code>3953caf</code></a>
docs: update README examples from <a
href="https://github.com/v8"><code>@​v8</code></a> to <a
href="https://github.com/v9"><code>@​v9</code></a>, add getOctokit docs
and v9 brea...</li>
<li><a
href="https://github.com/actions/github-script/commit/c17d55b90dcdb3d554d0027a6c180a7adc2daf78"><code>c17d55b</code></a>
ci: add getOctokit integration test job</li>
<li><a
href="https://github.com/actions/github-script/commit/a047196d9a02fe92098771cafbb98c2f1814e408"><code>a047196</code></a>
test: add getOctokit integration tests via callAsyncFunction</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/github-script/compare/v8...v9">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/github-script&package-manager=github_actions&previous-version=8&new-version=9)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
Pinned Tmds.DBus.Protocol at 0.21.3.
Adds `prefers-color-scheme: dark` media queries to the HTML pages shown
after OAuth authentication so they respect the browser/system light/dark
mode preference.

- [x] Add dark-mode styles to default OAuth success/failure HTML pages
in `OAuth2SystemWebBrowser.cs`
- [x] Add dark-mode styles to GitHub success/failure HTML pages in
`GitHubResources.resx`
- [x] Add dark-mode styles to Bitbucket success/failure HTML pages in
`BitbucketResources.resx`
- [x] Add `<meta name="color-scheme" content="light dark">` so
browser-painted UI follows the theme
- [x] Build all affected projects — succeeded
- [x] Run existing tests for affected projects — all pass
- [x] Address PR review: override AUI's light `#f5f5f5` background on
`#footer` / `#footer-logo` in Bitbucket dark-mode pages
Use ImportFromPemFile on modern .NET to resolve the SYSLIB0057
deprecation warning, while keeping the original Import call on
.NET Framework where the new API is not available.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
When suppressStreams is true, Git's stderr is redirected to a pipe but
then we only read stdout before waiting for exit. If Git writes lots
to stderr (for example when tracing is enabled), the stderr pipe can
fill, causing the Git process to block and GCM to hang while checking
repository state.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
If SymbolOutput is not set then there's a bug whereby we try and trim
the end '/' and '\' characters on a null value. Guard against this.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
In the OAuth device-code flow, the in-proc UI path the calling logic
creates a `CancellationTokenSource` and later calls `Cancel()` on that
CTS to close the dialog once the token is obtained (or the user
cancels).

However, `ShowDeviceCodeViaUiAsync` disregards the provided cancellation
token and passes `CancellationToken.None` into `AvaloniaUi.ShowViewAsync`.

Pass the cancellation token correctly.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
The `Thread::ManagedTheadId` always starts with the entry thread as `1`
and not `0`.

https://github.com/dotnet/runtime/blob/790e8a525a0f76b8ad755c12e95b7f8770195d67/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/ManagedThreadId.cs#L181

Fix this in Trace2.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
BuildTimeSpan assumes an 11-character span and adjusts padding when the
formatted elapsed time overflows. For values with 5+ digits before the
decimal (>= 10000 seconds), the size difference exceeds the available
padding budget, driving BeginPadding below zero. This causes
`new string(' ', BeginPadding)` to throw an ArgumentOutOfRangeException.

Since Trace2FileWriter does not catch exceptions, this crashes the
credential helper when TRACE2 performance output is enabled.

Fix the overflow check from `==` to `>=` so that values exceeding the
full span (data + padding) zero out all padding rather than producing a
negative value.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
We had been incorrectly looking for the `sslAutoClientCert` Git config
option under the `credential` section, rather than `http`.

Note: this is a Git for Windows only option.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
ReleaseManagedResources iterates forward by index while removing
elements from the same list. Each removal shifts remaining elements
left, but the loop increments i, causing the next element to be
skipped. As a result, only about half of the writers are disposed and
removed, leaving file handles or buffers open.

Fix by iterating in reverse so that removals do not shift any unvisited
indices, and use RemoveAt(i) to avoid a redundant linear search.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
ProcessManager.CreateProcess sets RedirectStandardError=false for all
processes to avoid TRACE2 deadlocks. However, GetRemotes and
CreateGitException unconditionally read StandardError, which throws
InvalidOperationException when stderr is not redirected.

Fix GetRemotes by explicitly redirecting stderr before starting the
process, since it needs to check for 'not a git repository' errors.
Guard CreateGitException defensively, as it is called from various
contexts where stderr may or may not be redirected.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
In f1a1ae5 (environment: manually scan $PATH on POSIX systems,
2022-05-31) the `which`-based lookup was replaced with a manual PATH
scan that only checks FileExists, without verifying execute permissions.
Unlike `which`, this means a non-executable file earlier in PATH can
shadow a valid executable, causing process creation to fail when GCM
later tries to run the located path.

Add an IsExecutable check that verifies at least one execute bit is set
on POSIX systems, matching the behaviour of `which`. On Windows, any
existing file is considered executable. Guard the POSIX-specific
File.GetUnixFileMode call with #if !NETFRAMEWORK for net472
compatibility.

https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03

> PATH
> [..] The list shall be searched from beginning to end, applying the
> filename to each prefix, until an executable file with the specified
> name and appropriate execution permissions is found

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
The powershell.exe invocation in the Installer.Windows.csproj Exec
task uses Unicode en dash characters (U+2013) instead of ASCII hyphens
for the -NonInteractive and -ExecutionPolicy parameters. Windows
PowerShell 5.1 does not recognise en dashes as parameter prefixes, so
these flags are not applied correctly, which can cause the layout step
to fail or run with an unexpected execution policy.

Replace the en dash characters with ASCII hyphens.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
A collection of small bug fixes found with the help of an AI agent
scanning the codebase. None of these are known to be actively exploited
or causing user-reported issues, but each is a latent defect that could
cause crashes, hangs, or incorrect behaviour under the right conditions.

## Fixes

**Credential UI** — `github/gitlab: use correct param order`
- Custom credential UI commands had swapped URL and username arguments.

**Stream extensions** — `streamextensions: fix a bug in multi-var reset
handling`
- Multi-dictionary writer emitted the wrong value when a reset marker
was followed by a single entry.

**GitHub auth** — `github: handle empty domain or enterprise hints`
- Null-reference exception when WWW-Authenticate header is missing
domain/enterprise hints.

**GitHub account filtering** — `github: do not filter accounts outside
of dotcom`
- Account filtering was applied outside of GitHub.com despite detecting
it shouldn't be.

**Network diagnostics** — `diagnose: fix network diag to await HTTP
requests`
- HTTP requests in the network diagnostic were not properly awaited.

**macOS notarize script** — `macos: add die function to notarize.sh
script`
- Missing `die` function.

**Git stderr handling** — `git: drain stderr on IsInsideRepository`
- Potential hang when Git writes enough to stderr to fill the pipe
buffer.

**Windows layout script** — `windows: fix layout.ps1 if symboloutput is
not set`
- Null-reference trimming `SymbolOutput` when the variable is unset.

**OAuth device code UI** — `oauth: pass cancellation token to in-proc
device code UI`
- Cancellation token was not forwarded, so dismissing the dialog didn't
work.

**TRACE2 thread ID** — `trace2: fix main thread identification`
- Main thread ID starts at 1, not 0.

**TRACE2 perf format** — `trace2: fix crash in perf format for large
elapsed times`
- `ArgumentOutOfRangeException` crash when elapsed time exceeds 9999
seconds.

**HTTP config** — `http: use correct http.sslAutoClientCert setting
name`
- Setting was read from the wrong Git config section.

**TRACE2 writer cleanup** — `trace2: fix incomplete disposal of writers
on cleanup`
- Forward iteration with removal skipped every other writer, leaking
file handles.

**Git stderr redirect** — `git: fix crash when reading stderr from
non-redirected processes`
- `InvalidOperationException` when `GetRemotes`/`CreateGitException`
read non-redirected stderr.

**Executable lookup** — `environment: check execute permission in
TryLocateExecutable`
- PATH scan didn't verify execute bits on POSIX, unlike the `which` it
replaced.

**Installer Exec command** — `windows: fix en-dash characters in
installer Exec command`
- Unicode en-dash characters instead of ASCII hyphens broke PowerShell
5.1 parameter parsing.
…2326)

Use `ImportFromPemFile` on modern .NET to resolve the `SYSLIB0057`
deprecation warning, while keeping the original `Import` call on .NET
Framework where the new API is not available.

We know this is always a PEM file since this is a Git defined option,
and it is passed to libcurl via `CURLINFO_CAINFO` which expects PEM
format.
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet)
from 5.1.0 to 5.2.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-dotnet/releases">actions/setup-dotnet's
releases</a>.</em></p>
<blockquote>
<h2>v5.2.0</h2>
<h2>What's changed</h2>
<h3>Enhancements</h3>
<ul>
<li>Add support for workloads input by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-dotnet/pull/693">actions/setup-dotnet#693</a></li>
<li>Add support for optional architecture input for cross-architecture
.NET installs by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-dotnet/pull/700">actions/setup-dotnet#700</a></li>
</ul>
<h3>Dependency Updates</h3>
<ul>
<li>Upgrade fast-xml-parser from 4.4.1 to 5.3.6 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/setup-dotnet/pull/671">actions/setup-dotnet#671</a></li>
<li>Upgrade minimatch from 3.1.2 to 3.1.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/setup-dotnet/pull/705">actions/setup-dotnet#705</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-dotnet/compare/v5...v5.2.0">https://github.com/actions/setup-dotnet/compare/v5...v5.2.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/setup-dotnet/commit/c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7"><code>c2fa09f</code></a>
Bump minimatch from 3.1.2 to 3.1.5 (<a
href="https://redirect.github.com/actions/setup-dotnet/issues/705">#705</a>)</li>
<li><a
href="https://github.com/actions/setup-dotnet/commit/02574b18e2dc57a218ee4e11ba1e1603c67236e8"><code>02574b1</code></a>
Add support for optional architecture input for cross-architecture .NET
insta...</li>
<li><a
href="https://github.com/actions/setup-dotnet/commit/16c7b3c2fa55a0e394467d22512b84fda46adf63"><code>16c7b3c</code></a>
Bump fast-xml-parser from 4.4.1 to 5.3.6 (<a
href="https://redirect.github.com/actions/setup-dotnet/issues/671">#671</a>)</li>
<li><a
href="https://github.com/actions/setup-dotnet/commit/131b410979e0b49e2162c0718030257b22d6dc2c"><code>131b410</code></a>
Add support for workloads input (<a
href="https://redirect.github.com/actions/setup-dotnet/issues/693">#693</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/setup-dotnet/compare/v5.1.0...v5.2.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/setup-dotnet&package-manager=github_actions&previous-version=5.1.0&new-version=5.2.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

You can trigger a rebase of this PR by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

> **Note**
> Automatic rebases have been disabled on this pull request as it has
been open for over 30 days.
Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
@mjcheetham mjcheetham requested review from a team as code owners April 28, 2026 10:04
Copy link
Copy Markdown
Contributor

@dscho dscho left a comment

Choose a reason for hiding this comment

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

🎉

The project now targets net10.0 but the install-from-source script
still referenced .NET SDK 8.0. Update all references to 10.0 and
fix the version parsing to use field-based extraction instead of
fixed-width character slicing, which broke for two-digit major
versions.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
.NET 10 no longer supports Debian 11 (bullseye). Update the
install-from-source CI matrix to use Debian 12 (bookworm).

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
The project now targets net10.0 but the install-from-source script still
referenced .NET SDK 8.0. Update all references to 10.0 and fix the
version parsing to use field-based extraction instead of fixed-width
character slicing, which broke for two-digit major versions.
@mjcheetham mjcheetham merged commit 3854378 into release Apr 28, 2026
26 checks passed
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.

10 participants