Release: two-phase dual-publish release model - #321

Closed
ptr727 wants to merge 31 commits into
mainfrom
develop
Closed

Release: two-phase dual-publish release model#321
ptr727 wants to merge 31 commits into
mainfrom
develop

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Summary

Release PR promoting the two-phase dual-publish release model from develop to main (squashed via #320).

On merge, this is the first main state with the new model: publish-release.yml becomes the sole publisher (weekly Monday 02:00 UTC + manual dispatch, both branches, idempotent), PRs smoke-test only, and a branch-aware Dependabot merge-bot replaces the legacy auto-merge. Also includes Central Package Management, AGENTS.md, documented analyzer relaxations for the strict template settings, and line-ending/husky-hook normalization.

See #320 for the full change description and Copilot review.

Maintainer follow-ups (after this merges)

  • Add CODEGEN_APP_CLIENT_ID / CODEGEN_APP_PRIVATE_KEY (GitHub App) to both Actions and Dependabot secret stores for the merge-bot.
  • Bind the Check pull request workflow status required check to the develop (squash-only) and main (merge-only) rulesets.
  • Leave PUBLISH_ON_MERGE unset for the two-phase default; trigger the first publish via publish-release.yml → Run workflow.

🤖 Generated with Claude Code

dependabotBotand others added 30 commits August 19, 2025 20:51
Bumps csharpier from 1.1.1 to 1.1.2
Bumps xunit.analyzers from 1.23.0 to 1.24.0
Bumps xunit.runner.visualstudio from 3.1.3 to 3.1.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.1.2
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
- dependency-name: xunit.analyzers
dependency-version: 1.24.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-0259308462
Bump the nuget-deps group with 3 updates
Bumps xunit.runner.visualstudio from 3.1.4 to 3.1.5
---
updated-dependencies:
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…evelop/nuget-deps-6aadeae1b1
Bump the nuget-deps group with 1 update
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-39349b7924
Bump csharpier from 1.1.2 to 1.2.1
---
updated-dependencies:
- dependency-name: Serilog.Sinks.Console
dependency-version: 6.1.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…nuget-deps-602f419b37
Bump Serilog.Sinks.Console from 6.0.0 to 6.1.1
Bumps csharpier from 1.2.1 to 1.2.3
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.3
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-1689e99d0a
Bump the nuget-deps group with 1 update
Bumps the actions-deps group with 2 updates in the / directory: [actions/setup-dotnet](https://github.com/actions/setup-dotnet) and [actions/checkout](https://github.com/actions/checkout).
Updates `actions/setup-dotnet` from 4 to 5
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](actions/setup-dotnet@v4...v5)
Updates `actions/checkout` from 5 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)
---
updated-dependencies:
- dependency-name: actions/setup-dotnet
dependency-version: '5'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
- dependency-name: actions/checkout
dependency-version: '6'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps csharpier from 1.2.3 to 1.2.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-133b2bc611
Bump the nuget-deps group with 1 update
Bumps csharpier from 1.2.4 to 1.2.5
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-262ca43251
Bump the nuget-deps group with 1 update
* Initial plan
* Add using statement and simplify CallerMemberName attributes
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Make HttpClient timeout configurable via TimeoutSeconds property
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Initial plan
* Replace redundant ToString() with string interpolation in FileExAsyncTests
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Replace explicit ToString() calls with string interpolation
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
…304)
Bumps the actions-deps group with 1 update: [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata).
Updates `dependabot/fetch-metadata` from 2 to 3
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](dependabot/fetch-metadata@v2...v3)
---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
dependency-version: '3'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Convert to two-phase dual-publish release model
Replace publish-on-push with the ProjectTemplate/LanguageTags two-phase
model: PRs smoke-test only, and publish-release.yml publishes both branches
on a weekly schedule (Mon 02:00 UTC) or manual dispatch, with idempotent
no-op republish. Adopt the reusable workflow set (get-version,
build-nugetlibrary, build-release, build-datebadge), a branch-aware
Dependabot merge-bot, Central Package Management, and an AGENTS.md tracking
the template. NuGet.org-only (drop GitHub Packages); no Docker/exe/PyPI/codegen.
Reconcile the template's strict analyzers (AnalysisMode All +
TreatWarningsAsErrors) with the brownfield library by relaxing specific
rules in .editorconfig and IL3058 via NoWarn, all documented.
* Normalize line endings to .editorconfig; fix husky hook
Convert the workflow YAML, dependabot.yml, and AGENTS.md (added LF) to CRLF
per .editorconfig, and make .husky/pre-commit LF + executable so its shebang
execs on Linux/WSL. Add an .editorconfig rule pinning the hook to LF.
* Quote "$GITHUB_OUTPUT" in date-badge task
CopilotAI review requested due to automatic review settings June 5, 2026 01:28

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Promotes the repository to the two-phase dual-publish release model (PRs smoke-test only; publishing centralized in publish-release.yml), while also modernizing the .NET solution to .NET 10/AOT and aligning build/test/package management with the template conventions for easier future upstream syncing.

Changes:

  • Replaces the legacy publish-on-push pipeline with reusable workflow tasks + branch-aware scheduled/manual publishing and a Dependabot merge-bot.
  • Introduces Central Package Management (Directory.Build.props / Directory.Packages.props) and normalizes solution/repo metadata (.slnx, AGENTS.md, .editorconfig).
  • Modernizes the Utilities library (AOT config, async APIs, improved XML docs) and expands xUnit coverage with new test files.

Reviewed changes

Copilot reviewed 45 out of 47 changed files in this pull request and generated 22 comments.

Show a summary per file
FileDescription
version.jsonBumps base version for NBGV-managed releases.
UtilitiesTests/UtilitiesTests.csprojMoves test deps to Central Package Management and inherits net10.0 from props.
UtilitiesTests/UtilitiesTests.csCleans up usings to rely on implicit usings.
UtilitiesTests/StringHistoryTests.csAdds coverage for StringHistory behavior.
UtilitiesTests/StringCompressionTests.csCleans up usings.
UtilitiesTests/StringCompressionAsyncTests.csAdds async compression/decompression test coverage.
UtilitiesTests/FileExAsyncTests.csAdds async FileEx API coverage.
UtilitiesTests/ExtensionsTests.csAdds coverage for compression/logger extension methods.
UtilitiesTests/DownloadTests.csCleans up usings.
UtilitiesTests/DownloadAsyncTests.csAdds async Download API tests.
UtilitiesTests/ConsoleTests.csReplaces placeholder test with ConsoleEx coverage.
Utilities/Utilities.csproj.userRemoves user-specific Visual Studio metadata from repo.
Utilities/Utilities.csprojEnables AOT-related properties, XML docs generation, and Husky bootstrapping target.
Utilities/StringHistory.csAdds XML docs, null checking, and refactors ToString() implementation.
Utilities/StringCompression.csAdds XML docs, compression level support, and async APIs with cancellation.
Utilities/ProcessEx.csRemoves legacy process wrapper API.
Utilities/LogOptions.csAdds XML documentation to global logger config.
Utilities/Format.csAdds XML docs and refactors byte-format logic.
Utilities/FileExOptions.csAdds XML docs and clarifies option semantics.
Utilities/FileEx.csAdds async variants, improves XML docs, refactors logging helpers, and adds new helpers.
Utilities/Extensions.csMigrates to C# extension blocks; adds compression + logger helpers with caller info.
Utilities/Download.csAdds async APIs, shared HttpClient via Lazy<>, and improves header-only requests.
Utilities/ConsoleEx.csAdds XML docs and improves null handling.
Utilities/CommandLineEx.csAdds XML docs and tweaks argument splitting behavior.
Utilities.slnxReplaces .sln with .slnx including solution items/workflow files.
Utilities.slnRemoves legacy Visual Studio solution file.
Sandbox/Sandbox.csprojAligns sandbox project with net10/AOT + central package mgmt.
Sandbox/Program.csAdjusts assembly base directory logic.
README.mdUpdates workflow badge and adds version history notes.
Directory.Packages.propsIntroduces centrally-managed package versions.
Directory.Build.propsIntroduces shared build settings (net10.0, analyzers, CPM).
AGENTS.mdDocuments branching/release/workflow conventions for humans/agents.
.husky/task-runner.jsonAdjusts dotnet format invocation settings.
.husky/pre-commitNormalizes pre-commit hook formatting/line endings.
.gitignoreAdds .artifacts and corrects .user ignore pattern.
.github/workflows/test-pull-request.ymlAdds PR smoke-test workflow with required-check aggregator job.
.github/workflows/publish-release.ymlAdds central publish workflow (schedule/dispatch; opt-in push publishing).
.github/workflows/merge-bot-pull-request.ymlAdds branch-aware Dependabot merge-bot with app-token strategy.
.github/workflows/get-version-task.ymlAdds reusable NBGV version-resolution task.
.github/workflows/DependabotAutoMerge.ymlRemoves legacy Dependabot auto-merge workflow.
.github/workflows/BuildPublishPipeline.ymlRemoves legacy build/publish pipeline workflow.
.github/workflows/build-release-task.ymlAdds reusable orchestrator for build + publish + GitHub release.
.github/workflows/build-nugetlibrary-task.ymlAdds reusable NuGet library build/push task.
.github/workflows/build-datebadge-task.ymlAdds reusable date-badge workflow.
.github/dependabot.ymlUpdates Dependabot config to dual-target main and develop with documentation.
.github/copilot-instructions.mdAdds repository-specific Copilot guidance (style/AOT/testing).
.editorconfigDocuments analyzer relaxations and adds Husky hook line-ending rule.
Comments suppressed due to low confidence (1)

Utilities/FileEx.cs:333

  • RenameFile compares directories via originalDirectory.Equals(...), which will throw if either path has no directory component (GetDirectoryName returns null). After allowing relative paths, use string.Equals to handle nulls safely.
 // Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{

Comment threadUtilities/FileEx.cs
Comment on lines +287 to +300
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +387 to +400
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +428 to +430
// Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{
Comment threadUtilities/FileEx.cs
Comment on lines +1146 to +1148
string? directory = Path.GetDirectoryName(filePath);
string fileName = $"{timeStamp:yyyyMMddTHHmmss}_{Path.GetFileName(filePath)}";
return Path.Combine(directory, fileName);
return Path.Combine(directory!, fileName);
Comment threadUtilities/FileEx.cs
Comment on lines +110 to +114
fileName
);
await Task.Delay(Options.RetryWaitTime * 1000, cancellationToken)
.ConfigureAwait(false);
}
{
private readonly UtilitiesTests _fixture = fixture;

[Fact]
Assert.True(size > 0);
}

[Fact]
Assert.Contains("google", content, StringComparison.OrdinalIgnoreCase);
}

[Fact]
}
}

[Fact]
Assert.False(success);
}

[Fact]
@ptr727

Copy link
Copy Markdown
OwnerAuthor

Superseded by the release branch PR release/dualpublishmain, which resolves the inherent old→new merge conflicts (develop wins + max dependency versions) so CI and Copilot can run on a conflict-free PR.

Sign up for freeto 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.

3 participants

@ptr727
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Release: two-phase dual-publish release model - #321

Closed
ptr727 wants to merge 31 commits into
mainfrom
develop
Closed

Release: two-phase dual-publish release model#321
ptr727 wants to merge 31 commits into
mainfrom
develop

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Summary

Release PR promoting the two-phase dual-publish release model from develop to main (squashed via #320).

On merge, this is the first main state with the new model: publish-release.yml becomes the sole publisher (weekly Monday 02:00 UTC + manual dispatch, both branches, idempotent), PRs smoke-test only, and a branch-aware Dependabot merge-bot replaces the legacy auto-merge. Also includes Central Package Management, AGENTS.md, documented analyzer relaxations for the strict template settings, and line-ending/husky-hook normalization.

See #320 for the full change description and Copilot review.

Maintainer follow-ups (after this merges)

  • Add CODEGEN_APP_CLIENT_ID / CODEGEN_APP_PRIVATE_KEY (GitHub App) to both Actions and Dependabot secret stores for the merge-bot.
  • Bind the Check pull request workflow status required check to the develop (squash-only) and main (merge-only) rulesets.
  • Leave PUBLISH_ON_MERGE unset for the two-phase default; trigger the first publish via publish-release.yml → Run workflow.

🤖 Generated with Claude Code

dependabotBotand others added 30 commits August 19, 2025 20:51
Bumps csharpier from 1.1.1 to 1.1.2
Bumps xunit.analyzers from 1.23.0 to 1.24.0
Bumps xunit.runner.visualstudio from 3.1.3 to 3.1.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.1.2
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
- dependency-name: xunit.analyzers
dependency-version: 1.24.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-0259308462
Bump the nuget-deps group with 3 updates
Bumps xunit.runner.visualstudio from 3.1.4 to 3.1.5
---
updated-dependencies:
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…evelop/nuget-deps-6aadeae1b1
Bump the nuget-deps group with 1 update
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-39349b7924
Bump csharpier from 1.1.2 to 1.2.1
---
updated-dependencies:
- dependency-name: Serilog.Sinks.Console
dependency-version: 6.1.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…nuget-deps-602f419b37
Bump Serilog.Sinks.Console from 6.0.0 to 6.1.1
Bumps csharpier from 1.2.1 to 1.2.3
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.3
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-1689e99d0a
Bump the nuget-deps group with 1 update
Bumps the actions-deps group with 2 updates in the / directory: [actions/setup-dotnet](https://github.com/actions/setup-dotnet) and [actions/checkout](https://github.com/actions/checkout).
Updates `actions/setup-dotnet` from 4 to 5
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](actions/setup-dotnet@v4...v5)
Updates `actions/checkout` from 5 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)
---
updated-dependencies:
- dependency-name: actions/setup-dotnet
dependency-version: '5'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
- dependency-name: actions/checkout
dependency-version: '6'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps csharpier from 1.2.3 to 1.2.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-133b2bc611
Bump the nuget-deps group with 1 update
Bumps csharpier from 1.2.4 to 1.2.5
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-262ca43251
Bump the nuget-deps group with 1 update
* Initial plan
* Add using statement and simplify CallerMemberName attributes
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Make HttpClient timeout configurable via TimeoutSeconds property
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Initial plan
* Replace redundant ToString() with string interpolation in FileExAsyncTests
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Replace explicit ToString() calls with string interpolation
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
…304)
Bumps the actions-deps group with 1 update: [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata).
Updates `dependabot/fetch-metadata` from 2 to 3
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](dependabot/fetch-metadata@v2...v3)
---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
dependency-version: '3'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Convert to two-phase dual-publish release model
Replace publish-on-push with the ProjectTemplate/LanguageTags two-phase
model: PRs smoke-test only, and publish-release.yml publishes both branches
on a weekly schedule (Mon 02:00 UTC) or manual dispatch, with idempotent
no-op republish. Adopt the reusable workflow set (get-version,
build-nugetlibrary, build-release, build-datebadge), a branch-aware
Dependabot merge-bot, Central Package Management, and an AGENTS.md tracking
the template. NuGet.org-only (drop GitHub Packages); no Docker/exe/PyPI/codegen.
Reconcile the template's strict analyzers (AnalysisMode All +
TreatWarningsAsErrors) with the brownfield library by relaxing specific
rules in .editorconfig and IL3058 via NoWarn, all documented.
* Normalize line endings to .editorconfig; fix husky hook
Convert the workflow YAML, dependabot.yml, and AGENTS.md (added LF) to CRLF
per .editorconfig, and make .husky/pre-commit LF + executable so its shebang
execs on Linux/WSL. Add an .editorconfig rule pinning the hook to LF.
* Quote "$GITHUB_OUTPUT" in date-badge task
CopilotAI review requested due to automatic review settings June 5, 2026 01:28

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Promotes the repository to the two-phase dual-publish release model (PRs smoke-test only; publishing centralized in publish-release.yml), while also modernizing the .NET solution to .NET 10/AOT and aligning build/test/package management with the template conventions for easier future upstream syncing.

Changes:

  • Replaces the legacy publish-on-push pipeline with reusable workflow tasks + branch-aware scheduled/manual publishing and a Dependabot merge-bot.
  • Introduces Central Package Management (Directory.Build.props / Directory.Packages.props) and normalizes solution/repo metadata (.slnx, AGENTS.md, .editorconfig).
  • Modernizes the Utilities library (AOT config, async APIs, improved XML docs) and expands xUnit coverage with new test files.

Reviewed changes

Copilot reviewed 45 out of 47 changed files in this pull request and generated 22 comments.

Show a summary per file
FileDescription
version.jsonBumps base version for NBGV-managed releases.
UtilitiesTests/UtilitiesTests.csprojMoves test deps to Central Package Management and inherits net10.0 from props.
UtilitiesTests/UtilitiesTests.csCleans up usings to rely on implicit usings.
UtilitiesTests/StringHistoryTests.csAdds coverage for StringHistory behavior.
UtilitiesTests/StringCompressionTests.csCleans up usings.
UtilitiesTests/StringCompressionAsyncTests.csAdds async compression/decompression test coverage.
UtilitiesTests/FileExAsyncTests.csAdds async FileEx API coverage.
UtilitiesTests/ExtensionsTests.csAdds coverage for compression/logger extension methods.
UtilitiesTests/DownloadTests.csCleans up usings.
UtilitiesTests/DownloadAsyncTests.csAdds async Download API tests.
UtilitiesTests/ConsoleTests.csReplaces placeholder test with ConsoleEx coverage.
Utilities/Utilities.csproj.userRemoves user-specific Visual Studio metadata from repo.
Utilities/Utilities.csprojEnables AOT-related properties, XML docs generation, and Husky bootstrapping target.
Utilities/StringHistory.csAdds XML docs, null checking, and refactors ToString() implementation.
Utilities/StringCompression.csAdds XML docs, compression level support, and async APIs with cancellation.
Utilities/ProcessEx.csRemoves legacy process wrapper API.
Utilities/LogOptions.csAdds XML documentation to global logger config.
Utilities/Format.csAdds XML docs and refactors byte-format logic.
Utilities/FileExOptions.csAdds XML docs and clarifies option semantics.
Utilities/FileEx.csAdds async variants, improves XML docs, refactors logging helpers, and adds new helpers.
Utilities/Extensions.csMigrates to C# extension blocks; adds compression + logger helpers with caller info.
Utilities/Download.csAdds async APIs, shared HttpClient via Lazy<>, and improves header-only requests.
Utilities/ConsoleEx.csAdds XML docs and improves null handling.
Utilities/CommandLineEx.csAdds XML docs and tweaks argument splitting behavior.
Utilities.slnxReplaces .sln with .slnx including solution items/workflow files.
Utilities.slnRemoves legacy Visual Studio solution file.
Sandbox/Sandbox.csprojAligns sandbox project with net10/AOT + central package mgmt.
Sandbox/Program.csAdjusts assembly base directory logic.
README.mdUpdates workflow badge and adds version history notes.
Directory.Packages.propsIntroduces centrally-managed package versions.
Directory.Build.propsIntroduces shared build settings (net10.0, analyzers, CPM).
AGENTS.mdDocuments branching/release/workflow conventions for humans/agents.
.husky/task-runner.jsonAdjusts dotnet format invocation settings.
.husky/pre-commitNormalizes pre-commit hook formatting/line endings.
.gitignoreAdds .artifacts and corrects .user ignore pattern.
.github/workflows/test-pull-request.ymlAdds PR smoke-test workflow with required-check aggregator job.
.github/workflows/publish-release.ymlAdds central publish workflow (schedule/dispatch; opt-in push publishing).
.github/workflows/merge-bot-pull-request.ymlAdds branch-aware Dependabot merge-bot with app-token strategy.
.github/workflows/get-version-task.ymlAdds reusable NBGV version-resolution task.
.github/workflows/DependabotAutoMerge.ymlRemoves legacy Dependabot auto-merge workflow.
.github/workflows/BuildPublishPipeline.ymlRemoves legacy build/publish pipeline workflow.
.github/workflows/build-release-task.ymlAdds reusable orchestrator for build + publish + GitHub release.
.github/workflows/build-nugetlibrary-task.ymlAdds reusable NuGet library build/push task.
.github/workflows/build-datebadge-task.ymlAdds reusable date-badge workflow.
.github/dependabot.ymlUpdates Dependabot config to dual-target main and develop with documentation.
.github/copilot-instructions.mdAdds repository-specific Copilot guidance (style/AOT/testing).
.editorconfigDocuments analyzer relaxations and adds Husky hook line-ending rule.
Comments suppressed due to low confidence (1)

Utilities/FileEx.cs:333

  • RenameFile compares directories via originalDirectory.Equals(...), which will throw if either path has no directory component (GetDirectoryName returns null). After allowing relative paths, use string.Equals to handle nulls safely.
 // Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{

Comment threadUtilities/FileEx.cs
Comment on lines +287 to +300
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +387 to +400
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +428 to +430
// Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{
Comment threadUtilities/FileEx.cs
Comment on lines +1146 to +1148
string? directory = Path.GetDirectoryName(filePath);
string fileName = $"{timeStamp:yyyyMMddTHHmmss}_{Path.GetFileName(filePath)}";
return Path.Combine(directory, fileName);
return Path.Combine(directory!, fileName);
Comment threadUtilities/FileEx.cs
Comment on lines +110 to +114
fileName
);
await Task.Delay(Options.RetryWaitTime * 1000, cancellationToken)
.ConfigureAwait(false);
}
{
private readonly UtilitiesTests _fixture = fixture;

[Fact]
Assert.True(size > 0);
}

[Fact]
Assert.Contains("google", content, StringComparison.OrdinalIgnoreCase);
}

[Fact]
}
}

[Fact]
Assert.False(success);
}

[Fact]
@ptr727

Copy link
Copy Markdown
OwnerAuthor

Superseded by the release branch PR release/dualpublishmain, which resolves the inherent old→new merge conflicts (develop wins + max dependency versions) so CI and Copilot can run on a conflict-free PR.

Sign up for freeto 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.

3 participants

@ptr727
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Release: two-phase dual-publish release model - #321

Closed
ptr727 wants to merge 31 commits into
mainfrom
develop
Closed

Release: two-phase dual-publish release model#321
ptr727 wants to merge 31 commits into
mainfrom
develop

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Summary

Release PR promoting the two-phase dual-publish release model from develop to main (squashed via #320).

On merge, this is the first main state with the new model: publish-release.yml becomes the sole publisher (weekly Monday 02:00 UTC + manual dispatch, both branches, idempotent), PRs smoke-test only, and a branch-aware Dependabot merge-bot replaces the legacy auto-merge. Also includes Central Package Management, AGENTS.md, documented analyzer relaxations for the strict template settings, and line-ending/husky-hook normalization.

See #320 for the full change description and Copilot review.

Maintainer follow-ups (after this merges)

  • Add CODEGEN_APP_CLIENT_ID / CODEGEN_APP_PRIVATE_KEY (GitHub App) to both Actions and Dependabot secret stores for the merge-bot.
  • Bind the Check pull request workflow status required check to the develop (squash-only) and main (merge-only) rulesets.
  • Leave PUBLISH_ON_MERGE unset for the two-phase default; trigger the first publish via publish-release.yml → Run workflow.

🤖 Generated with Claude Code

dependabotBotand others added 30 commits August 19, 2025 20:51
Bumps csharpier from 1.1.1 to 1.1.2
Bumps xunit.analyzers from 1.23.0 to 1.24.0
Bumps xunit.runner.visualstudio from 3.1.3 to 3.1.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.1.2
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
- dependency-name: xunit.analyzers
dependency-version: 1.24.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-0259308462
Bump the nuget-deps group with 3 updates
Bumps xunit.runner.visualstudio from 3.1.4 to 3.1.5
---
updated-dependencies:
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…evelop/nuget-deps-6aadeae1b1
Bump the nuget-deps group with 1 update
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-39349b7924
Bump csharpier from 1.1.2 to 1.2.1
---
updated-dependencies:
- dependency-name: Serilog.Sinks.Console
dependency-version: 6.1.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…nuget-deps-602f419b37
Bump Serilog.Sinks.Console from 6.0.0 to 6.1.1
Bumps csharpier from 1.2.1 to 1.2.3
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.3
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-1689e99d0a
Bump the nuget-deps group with 1 update
Bumps the actions-deps group with 2 updates in the / directory: [actions/setup-dotnet](https://github.com/actions/setup-dotnet) and [actions/checkout](https://github.com/actions/checkout).
Updates `actions/setup-dotnet` from 4 to 5
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](actions/setup-dotnet@v4...v5)
Updates `actions/checkout` from 5 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)
---
updated-dependencies:
- dependency-name: actions/setup-dotnet
dependency-version: '5'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
- dependency-name: actions/checkout
dependency-version: '6'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps csharpier from 1.2.3 to 1.2.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-133b2bc611
Bump the nuget-deps group with 1 update
Bumps csharpier from 1.2.4 to 1.2.5
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-262ca43251
Bump the nuget-deps group with 1 update
* Initial plan
* Add using statement and simplify CallerMemberName attributes
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Make HttpClient timeout configurable via TimeoutSeconds property
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Initial plan
* Replace redundant ToString() with string interpolation in FileExAsyncTests
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Replace explicit ToString() calls with string interpolation
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
…304)
Bumps the actions-deps group with 1 update: [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata).
Updates `dependabot/fetch-metadata` from 2 to 3
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](dependabot/fetch-metadata@v2...v3)
---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
dependency-version: '3'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Convert to two-phase dual-publish release model
Replace publish-on-push with the ProjectTemplate/LanguageTags two-phase
model: PRs smoke-test only, and publish-release.yml publishes both branches
on a weekly schedule (Mon 02:00 UTC) or manual dispatch, with idempotent
no-op republish. Adopt the reusable workflow set (get-version,
build-nugetlibrary, build-release, build-datebadge), a branch-aware
Dependabot merge-bot, Central Package Management, and an AGENTS.md tracking
the template. NuGet.org-only (drop GitHub Packages); no Docker/exe/PyPI/codegen.
Reconcile the template's strict analyzers (AnalysisMode All +
TreatWarningsAsErrors) with the brownfield library by relaxing specific
rules in .editorconfig and IL3058 via NoWarn, all documented.
* Normalize line endings to .editorconfig; fix husky hook
Convert the workflow YAML, dependabot.yml, and AGENTS.md (added LF) to CRLF
per .editorconfig, and make .husky/pre-commit LF + executable so its shebang
execs on Linux/WSL. Add an .editorconfig rule pinning the hook to LF.
* Quote "$GITHUB_OUTPUT" in date-badge task
CopilotAI review requested due to automatic review settings June 5, 2026 01:28

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Promotes the repository to the two-phase dual-publish release model (PRs smoke-test only; publishing centralized in publish-release.yml), while also modernizing the .NET solution to .NET 10/AOT and aligning build/test/package management with the template conventions for easier future upstream syncing.

Changes:

  • Replaces the legacy publish-on-push pipeline with reusable workflow tasks + branch-aware scheduled/manual publishing and a Dependabot merge-bot.
  • Introduces Central Package Management (Directory.Build.props / Directory.Packages.props) and normalizes solution/repo metadata (.slnx, AGENTS.md, .editorconfig).
  • Modernizes the Utilities library (AOT config, async APIs, improved XML docs) and expands xUnit coverage with new test files.

Reviewed changes

Copilot reviewed 45 out of 47 changed files in this pull request and generated 22 comments.

Show a summary per file
FileDescription
version.jsonBumps base version for NBGV-managed releases.
UtilitiesTests/UtilitiesTests.csprojMoves test deps to Central Package Management and inherits net10.0 from props.
UtilitiesTests/UtilitiesTests.csCleans up usings to rely on implicit usings.
UtilitiesTests/StringHistoryTests.csAdds coverage for StringHistory behavior.
UtilitiesTests/StringCompressionTests.csCleans up usings.
UtilitiesTests/StringCompressionAsyncTests.csAdds async compression/decompression test coverage.
UtilitiesTests/FileExAsyncTests.csAdds async FileEx API coverage.
UtilitiesTests/ExtensionsTests.csAdds coverage for compression/logger extension methods.
UtilitiesTests/DownloadTests.csCleans up usings.
UtilitiesTests/DownloadAsyncTests.csAdds async Download API tests.
UtilitiesTests/ConsoleTests.csReplaces placeholder test with ConsoleEx coverage.
Utilities/Utilities.csproj.userRemoves user-specific Visual Studio metadata from repo.
Utilities/Utilities.csprojEnables AOT-related properties, XML docs generation, and Husky bootstrapping target.
Utilities/StringHistory.csAdds XML docs, null checking, and refactors ToString() implementation.
Utilities/StringCompression.csAdds XML docs, compression level support, and async APIs with cancellation.
Utilities/ProcessEx.csRemoves legacy process wrapper API.
Utilities/LogOptions.csAdds XML documentation to global logger config.
Utilities/Format.csAdds XML docs and refactors byte-format logic.
Utilities/FileExOptions.csAdds XML docs and clarifies option semantics.
Utilities/FileEx.csAdds async variants, improves XML docs, refactors logging helpers, and adds new helpers.
Utilities/Extensions.csMigrates to C# extension blocks; adds compression + logger helpers with caller info.
Utilities/Download.csAdds async APIs, shared HttpClient via Lazy<>, and improves header-only requests.
Utilities/ConsoleEx.csAdds XML docs and improves null handling.
Utilities/CommandLineEx.csAdds XML docs and tweaks argument splitting behavior.
Utilities.slnxReplaces .sln with .slnx including solution items/workflow files.
Utilities.slnRemoves legacy Visual Studio solution file.
Sandbox/Sandbox.csprojAligns sandbox project with net10/AOT + central package mgmt.
Sandbox/Program.csAdjusts assembly base directory logic.
README.mdUpdates workflow badge and adds version history notes.
Directory.Packages.propsIntroduces centrally-managed package versions.
Directory.Build.propsIntroduces shared build settings (net10.0, analyzers, CPM).
AGENTS.mdDocuments branching/release/workflow conventions for humans/agents.
.husky/task-runner.jsonAdjusts dotnet format invocation settings.
.husky/pre-commitNormalizes pre-commit hook formatting/line endings.
.gitignoreAdds .artifacts and corrects .user ignore pattern.
.github/workflows/test-pull-request.ymlAdds PR smoke-test workflow with required-check aggregator job.
.github/workflows/publish-release.ymlAdds central publish workflow (schedule/dispatch; opt-in push publishing).
.github/workflows/merge-bot-pull-request.ymlAdds branch-aware Dependabot merge-bot with app-token strategy.
.github/workflows/get-version-task.ymlAdds reusable NBGV version-resolution task.
.github/workflows/DependabotAutoMerge.ymlRemoves legacy Dependabot auto-merge workflow.
.github/workflows/BuildPublishPipeline.ymlRemoves legacy build/publish pipeline workflow.
.github/workflows/build-release-task.ymlAdds reusable orchestrator for build + publish + GitHub release.
.github/workflows/build-nugetlibrary-task.ymlAdds reusable NuGet library build/push task.
.github/workflows/build-datebadge-task.ymlAdds reusable date-badge workflow.
.github/dependabot.ymlUpdates Dependabot config to dual-target main and develop with documentation.
.github/copilot-instructions.mdAdds repository-specific Copilot guidance (style/AOT/testing).
.editorconfigDocuments analyzer relaxations and adds Husky hook line-ending rule.
Comments suppressed due to low confidence (1)

Utilities/FileEx.cs:333

  • RenameFile compares directories via originalDirectory.Equals(...), which will throw if either path has no directory component (GetDirectoryName returns null). After allowing relative paths, use string.Equals to handle nulls safely.
 // Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{

Comment threadUtilities/FileEx.cs
Comment on lines +287 to +300
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +387 to +400
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +428 to +430
// Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{
Comment threadUtilities/FileEx.cs
Comment on lines +1146 to +1148
string? directory = Path.GetDirectoryName(filePath);
string fileName = $"{timeStamp:yyyyMMddTHHmmss}_{Path.GetFileName(filePath)}";
return Path.Combine(directory, fileName);
return Path.Combine(directory!, fileName);
Comment threadUtilities/FileEx.cs
Comment on lines +110 to +114
fileName
);
await Task.Delay(Options.RetryWaitTime * 1000, cancellationToken)
.ConfigureAwait(false);
}
{
private readonly UtilitiesTests _fixture = fixture;

[Fact]
Assert.True(size > 0);
}

[Fact]
Assert.Contains("google", content, StringComparison.OrdinalIgnoreCase);
}

[Fact]
}
}

[Fact]
Assert.False(success);
}

[Fact]
@ptr727

Copy link
Copy Markdown
OwnerAuthor

Superseded by the release branch PR release/dualpublishmain, which resolves the inherent old→new merge conflicts (develop wins + max dependency versions) so CI and Copilot can run on a conflict-free PR.

Sign up for freeto 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.

3 participants

@ptr727
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Release: two-phase dual-publish release model - #321

Closed
ptr727 wants to merge 31 commits into
mainfrom
develop
Closed

Release: two-phase dual-publish release model#321
ptr727 wants to merge 31 commits into
mainfrom
develop

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Summary

Release PR promoting the two-phase dual-publish release model from develop to main (squashed via #320).

On merge, this is the first main state with the new model: publish-release.yml becomes the sole publisher (weekly Monday 02:00 UTC + manual dispatch, both branches, idempotent), PRs smoke-test only, and a branch-aware Dependabot merge-bot replaces the legacy auto-merge. Also includes Central Package Management, AGENTS.md, documented analyzer relaxations for the strict template settings, and line-ending/husky-hook normalization.

See #320 for the full change description and Copilot review.

Maintainer follow-ups (after this merges)

  • Add CODEGEN_APP_CLIENT_ID / CODEGEN_APP_PRIVATE_KEY (GitHub App) to both Actions and Dependabot secret stores for the merge-bot.
  • Bind the Check pull request workflow status required check to the develop (squash-only) and main (merge-only) rulesets.
  • Leave PUBLISH_ON_MERGE unset for the two-phase default; trigger the first publish via publish-release.yml → Run workflow.

🤖 Generated with Claude Code

dependabotBotand others added 30 commits August 19, 2025 20:51
Bumps csharpier from 1.1.1 to 1.1.2
Bumps xunit.analyzers from 1.23.0 to 1.24.0
Bumps xunit.runner.visualstudio from 3.1.3 to 3.1.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.1.2
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
- dependency-name: xunit.analyzers
dependency-version: 1.24.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-0259308462
Bump the nuget-deps group with 3 updates
Bumps xunit.runner.visualstudio from 3.1.4 to 3.1.5
---
updated-dependencies:
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…evelop/nuget-deps-6aadeae1b1
Bump the nuget-deps group with 1 update
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-39349b7924
Bump csharpier from 1.1.2 to 1.2.1
---
updated-dependencies:
- dependency-name: Serilog.Sinks.Console
dependency-version: 6.1.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…nuget-deps-602f419b37
Bump Serilog.Sinks.Console from 6.0.0 to 6.1.1
Bumps csharpier from 1.2.1 to 1.2.3
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.3
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-1689e99d0a
Bump the nuget-deps group with 1 update
Bumps the actions-deps group with 2 updates in the / directory: [actions/setup-dotnet](https://github.com/actions/setup-dotnet) and [actions/checkout](https://github.com/actions/checkout).
Updates `actions/setup-dotnet` from 4 to 5
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](actions/setup-dotnet@v4...v5)
Updates `actions/checkout` from 5 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)
---
updated-dependencies:
- dependency-name: actions/setup-dotnet
dependency-version: '5'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
- dependency-name: actions/checkout
dependency-version: '6'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps csharpier from 1.2.3 to 1.2.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-133b2bc611
Bump the nuget-deps group with 1 update
Bumps csharpier from 1.2.4 to 1.2.5
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-262ca43251
Bump the nuget-deps group with 1 update
* Initial plan
* Add using statement and simplify CallerMemberName attributes
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Make HttpClient timeout configurable via TimeoutSeconds property
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Initial plan
* Replace redundant ToString() with string interpolation in FileExAsyncTests
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Replace explicit ToString() calls with string interpolation
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
…304)
Bumps the actions-deps group with 1 update: [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata).
Updates `dependabot/fetch-metadata` from 2 to 3
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](dependabot/fetch-metadata@v2...v3)
---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
dependency-version: '3'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Convert to two-phase dual-publish release model
Replace publish-on-push with the ProjectTemplate/LanguageTags two-phase
model: PRs smoke-test only, and publish-release.yml publishes both branches
on a weekly schedule (Mon 02:00 UTC) or manual dispatch, with idempotent
no-op republish. Adopt the reusable workflow set (get-version,
build-nugetlibrary, build-release, build-datebadge), a branch-aware
Dependabot merge-bot, Central Package Management, and an AGENTS.md tracking
the template. NuGet.org-only (drop GitHub Packages); no Docker/exe/PyPI/codegen.
Reconcile the template's strict analyzers (AnalysisMode All +
TreatWarningsAsErrors) with the brownfield library by relaxing specific
rules in .editorconfig and IL3058 via NoWarn, all documented.
* Normalize line endings to .editorconfig; fix husky hook
Convert the workflow YAML, dependabot.yml, and AGENTS.md (added LF) to CRLF
per .editorconfig, and make .husky/pre-commit LF + executable so its shebang
execs on Linux/WSL. Add an .editorconfig rule pinning the hook to LF.
* Quote "$GITHUB_OUTPUT" in date-badge task
CopilotAI review requested due to automatic review settings June 5, 2026 01:28

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Promotes the repository to the two-phase dual-publish release model (PRs smoke-test only; publishing centralized in publish-release.yml), while also modernizing the .NET solution to .NET 10/AOT and aligning build/test/package management with the template conventions for easier future upstream syncing.

Changes:

  • Replaces the legacy publish-on-push pipeline with reusable workflow tasks + branch-aware scheduled/manual publishing and a Dependabot merge-bot.
  • Introduces Central Package Management (Directory.Build.props / Directory.Packages.props) and normalizes solution/repo metadata (.slnx, AGENTS.md, .editorconfig).
  • Modernizes the Utilities library (AOT config, async APIs, improved XML docs) and expands xUnit coverage with new test files.

Reviewed changes

Copilot reviewed 45 out of 47 changed files in this pull request and generated 22 comments.

Show a summary per file
FileDescription
version.jsonBumps base version for NBGV-managed releases.
UtilitiesTests/UtilitiesTests.csprojMoves test deps to Central Package Management and inherits net10.0 from props.
UtilitiesTests/UtilitiesTests.csCleans up usings to rely on implicit usings.
UtilitiesTests/StringHistoryTests.csAdds coverage for StringHistory behavior.
UtilitiesTests/StringCompressionTests.csCleans up usings.
UtilitiesTests/StringCompressionAsyncTests.csAdds async compression/decompression test coverage.
UtilitiesTests/FileExAsyncTests.csAdds async FileEx API coverage.
UtilitiesTests/ExtensionsTests.csAdds coverage for compression/logger extension methods.
UtilitiesTests/DownloadTests.csCleans up usings.
UtilitiesTests/DownloadAsyncTests.csAdds async Download API tests.
UtilitiesTests/ConsoleTests.csReplaces placeholder test with ConsoleEx coverage.
Utilities/Utilities.csproj.userRemoves user-specific Visual Studio metadata from repo.
Utilities/Utilities.csprojEnables AOT-related properties, XML docs generation, and Husky bootstrapping target.
Utilities/StringHistory.csAdds XML docs, null checking, and refactors ToString() implementation.
Utilities/StringCompression.csAdds XML docs, compression level support, and async APIs with cancellation.
Utilities/ProcessEx.csRemoves legacy process wrapper API.
Utilities/LogOptions.csAdds XML documentation to global logger config.
Utilities/Format.csAdds XML docs and refactors byte-format logic.
Utilities/FileExOptions.csAdds XML docs and clarifies option semantics.
Utilities/FileEx.csAdds async variants, improves XML docs, refactors logging helpers, and adds new helpers.
Utilities/Extensions.csMigrates to C# extension blocks; adds compression + logger helpers with caller info.
Utilities/Download.csAdds async APIs, shared HttpClient via Lazy<>, and improves header-only requests.
Utilities/ConsoleEx.csAdds XML docs and improves null handling.
Utilities/CommandLineEx.csAdds XML docs and tweaks argument splitting behavior.
Utilities.slnxReplaces .sln with .slnx including solution items/workflow files.
Utilities.slnRemoves legacy Visual Studio solution file.
Sandbox/Sandbox.csprojAligns sandbox project with net10/AOT + central package mgmt.
Sandbox/Program.csAdjusts assembly base directory logic.
README.mdUpdates workflow badge and adds version history notes.
Directory.Packages.propsIntroduces centrally-managed package versions.
Directory.Build.propsIntroduces shared build settings (net10.0, analyzers, CPM).
AGENTS.mdDocuments branching/release/workflow conventions for humans/agents.
.husky/task-runner.jsonAdjusts dotnet format invocation settings.
.husky/pre-commitNormalizes pre-commit hook formatting/line endings.
.gitignoreAdds .artifacts and corrects .user ignore pattern.
.github/workflows/test-pull-request.ymlAdds PR smoke-test workflow with required-check aggregator job.
.github/workflows/publish-release.ymlAdds central publish workflow (schedule/dispatch; opt-in push publishing).
.github/workflows/merge-bot-pull-request.ymlAdds branch-aware Dependabot merge-bot with app-token strategy.
.github/workflows/get-version-task.ymlAdds reusable NBGV version-resolution task.
.github/workflows/DependabotAutoMerge.ymlRemoves legacy Dependabot auto-merge workflow.
.github/workflows/BuildPublishPipeline.ymlRemoves legacy build/publish pipeline workflow.
.github/workflows/build-release-task.ymlAdds reusable orchestrator for build + publish + GitHub release.
.github/workflows/build-nugetlibrary-task.ymlAdds reusable NuGet library build/push task.
.github/workflows/build-datebadge-task.ymlAdds reusable date-badge workflow.
.github/dependabot.ymlUpdates Dependabot config to dual-target main and develop with documentation.
.github/copilot-instructions.mdAdds repository-specific Copilot guidance (style/AOT/testing).
.editorconfigDocuments analyzer relaxations and adds Husky hook line-ending rule.
Comments suppressed due to low confidence (1)

Utilities/FileEx.cs:333

  • RenameFile compares directories via originalDirectory.Equals(...), which will throw if either path has no directory component (GetDirectoryName returns null). After allowing relative paths, use string.Equals to handle nulls safely.
 // Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{

Comment threadUtilities/FileEx.cs
Comment on lines +287 to +300
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +387 to +400
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +428 to +430
// Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{
Comment threadUtilities/FileEx.cs
Comment on lines +1146 to +1148
string? directory = Path.GetDirectoryName(filePath);
string fileName = $"{timeStamp:yyyyMMddTHHmmss}_{Path.GetFileName(filePath)}";
return Path.Combine(directory, fileName);
return Path.Combine(directory!, fileName);
Comment threadUtilities/FileEx.cs
Comment on lines +110 to +114
fileName
);
await Task.Delay(Options.RetryWaitTime * 1000, cancellationToken)
.ConfigureAwait(false);
}
{
private readonly UtilitiesTests _fixture = fixture;

[Fact]
Assert.True(size > 0);
}

[Fact]
Assert.Contains("google", content, StringComparison.OrdinalIgnoreCase);
}

[Fact]
}
}

[Fact]
Assert.False(success);
}

[Fact]
@ptr727

Copy link
Copy Markdown
OwnerAuthor

Superseded by the release branch PR release/dualpublishmain, which resolves the inherent old→new merge conflicts (develop wins + max dependency versions) so CI and Copilot can run on a conflict-free PR.

Sign up for freeto 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.

3 participants

@ptr727
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Release: two-phase dual-publish release model - #321

Closed
ptr727 wants to merge 31 commits into
mainfrom
develop
Closed

Release: two-phase dual-publish release model#321
ptr727 wants to merge 31 commits into
mainfrom
develop

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Summary

Release PR promoting the two-phase dual-publish release model from develop to main (squashed via #320).

On merge, this is the first main state with the new model: publish-release.yml becomes the sole publisher (weekly Monday 02:00 UTC + manual dispatch, both branches, idempotent), PRs smoke-test only, and a branch-aware Dependabot merge-bot replaces the legacy auto-merge. Also includes Central Package Management, AGENTS.md, documented analyzer relaxations for the strict template settings, and line-ending/husky-hook normalization.

See #320 for the full change description and Copilot review.

Maintainer follow-ups (after this merges)

  • Add CODEGEN_APP_CLIENT_ID / CODEGEN_APP_PRIVATE_KEY (GitHub App) to both Actions and Dependabot secret stores for the merge-bot.
  • Bind the Check pull request workflow status required check to the develop (squash-only) and main (merge-only) rulesets.
  • Leave PUBLISH_ON_MERGE unset for the two-phase default; trigger the first publish via publish-release.yml → Run workflow.

🤖 Generated with Claude Code

dependabotBotand others added 30 commits August 19, 2025 20:51
Bumps csharpier from 1.1.1 to 1.1.2
Bumps xunit.analyzers from 1.23.0 to 1.24.0
Bumps xunit.runner.visualstudio from 3.1.3 to 3.1.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.1.2
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
- dependency-name: xunit.analyzers
dependency-version: 1.24.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-0259308462
Bump the nuget-deps group with 3 updates
Bumps xunit.runner.visualstudio from 3.1.4 to 3.1.5
---
updated-dependencies:
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…evelop/nuget-deps-6aadeae1b1
Bump the nuget-deps group with 1 update
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-39349b7924
Bump csharpier from 1.1.2 to 1.2.1
---
updated-dependencies:
- dependency-name: Serilog.Sinks.Console
dependency-version: 6.1.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…nuget-deps-602f419b37
Bump Serilog.Sinks.Console from 6.0.0 to 6.1.1
Bumps csharpier from 1.2.1 to 1.2.3
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.3
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-1689e99d0a
Bump the nuget-deps group with 1 update
Bumps the actions-deps group with 2 updates in the / directory: [actions/setup-dotnet](https://github.com/actions/setup-dotnet) and [actions/checkout](https://github.com/actions/checkout).
Updates `actions/setup-dotnet` from 4 to 5
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](actions/setup-dotnet@v4...v5)
Updates `actions/checkout` from 5 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)
---
updated-dependencies:
- dependency-name: actions/setup-dotnet
dependency-version: '5'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
- dependency-name: actions/checkout
dependency-version: '6'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps csharpier from 1.2.3 to 1.2.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-133b2bc611
Bump the nuget-deps group with 1 update
Bumps csharpier from 1.2.4 to 1.2.5
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-262ca43251
Bump the nuget-deps group with 1 update
* Initial plan
* Add using statement and simplify CallerMemberName attributes
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Make HttpClient timeout configurable via TimeoutSeconds property
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Initial plan
* Replace redundant ToString() with string interpolation in FileExAsyncTests
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Replace explicit ToString() calls with string interpolation
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
…304)
Bumps the actions-deps group with 1 update: [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata).
Updates `dependabot/fetch-metadata` from 2 to 3
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](dependabot/fetch-metadata@v2...v3)
---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
dependency-version: '3'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Convert to two-phase dual-publish release model
Replace publish-on-push with the ProjectTemplate/LanguageTags two-phase
model: PRs smoke-test only, and publish-release.yml publishes both branches
on a weekly schedule (Mon 02:00 UTC) or manual dispatch, with idempotent
no-op republish. Adopt the reusable workflow set (get-version,
build-nugetlibrary, build-release, build-datebadge), a branch-aware
Dependabot merge-bot, Central Package Management, and an AGENTS.md tracking
the template. NuGet.org-only (drop GitHub Packages); no Docker/exe/PyPI/codegen.
Reconcile the template's strict analyzers (AnalysisMode All +
TreatWarningsAsErrors) with the brownfield library by relaxing specific
rules in .editorconfig and IL3058 via NoWarn, all documented.
* Normalize line endings to .editorconfig; fix husky hook
Convert the workflow YAML, dependabot.yml, and AGENTS.md (added LF) to CRLF
per .editorconfig, and make .husky/pre-commit LF + executable so its shebang
execs on Linux/WSL. Add an .editorconfig rule pinning the hook to LF.
* Quote "$GITHUB_OUTPUT" in date-badge task
CopilotAI review requested due to automatic review settings June 5, 2026 01:28

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Promotes the repository to the two-phase dual-publish release model (PRs smoke-test only; publishing centralized in publish-release.yml), while also modernizing the .NET solution to .NET 10/AOT and aligning build/test/package management with the template conventions for easier future upstream syncing.

Changes:

  • Replaces the legacy publish-on-push pipeline with reusable workflow tasks + branch-aware scheduled/manual publishing and a Dependabot merge-bot.
  • Introduces Central Package Management (Directory.Build.props / Directory.Packages.props) and normalizes solution/repo metadata (.slnx, AGENTS.md, .editorconfig).
  • Modernizes the Utilities library (AOT config, async APIs, improved XML docs) and expands xUnit coverage with new test files.

Reviewed changes

Copilot reviewed 45 out of 47 changed files in this pull request and generated 22 comments.

Show a summary per file
FileDescription
version.jsonBumps base version for NBGV-managed releases.
UtilitiesTests/UtilitiesTests.csprojMoves test deps to Central Package Management and inherits net10.0 from props.
UtilitiesTests/UtilitiesTests.csCleans up usings to rely on implicit usings.
UtilitiesTests/StringHistoryTests.csAdds coverage for StringHistory behavior.
UtilitiesTests/StringCompressionTests.csCleans up usings.
UtilitiesTests/StringCompressionAsyncTests.csAdds async compression/decompression test coverage.
UtilitiesTests/FileExAsyncTests.csAdds async FileEx API coverage.
UtilitiesTests/ExtensionsTests.csAdds coverage for compression/logger extension methods.
UtilitiesTests/DownloadTests.csCleans up usings.
UtilitiesTests/DownloadAsyncTests.csAdds async Download API tests.
UtilitiesTests/ConsoleTests.csReplaces placeholder test with ConsoleEx coverage.
Utilities/Utilities.csproj.userRemoves user-specific Visual Studio metadata from repo.
Utilities/Utilities.csprojEnables AOT-related properties, XML docs generation, and Husky bootstrapping target.
Utilities/StringHistory.csAdds XML docs, null checking, and refactors ToString() implementation.
Utilities/StringCompression.csAdds XML docs, compression level support, and async APIs with cancellation.
Utilities/ProcessEx.csRemoves legacy process wrapper API.
Utilities/LogOptions.csAdds XML documentation to global logger config.
Utilities/Format.csAdds XML docs and refactors byte-format logic.
Utilities/FileExOptions.csAdds XML docs and clarifies option semantics.
Utilities/FileEx.csAdds async variants, improves XML docs, refactors logging helpers, and adds new helpers.
Utilities/Extensions.csMigrates to C# extension blocks; adds compression + logger helpers with caller info.
Utilities/Download.csAdds async APIs, shared HttpClient via Lazy<>, and improves header-only requests.
Utilities/ConsoleEx.csAdds XML docs and improves null handling.
Utilities/CommandLineEx.csAdds XML docs and tweaks argument splitting behavior.
Utilities.slnxReplaces .sln with .slnx including solution items/workflow files.
Utilities.slnRemoves legacy Visual Studio solution file.
Sandbox/Sandbox.csprojAligns sandbox project with net10/AOT + central package mgmt.
Sandbox/Program.csAdjusts assembly base directory logic.
README.mdUpdates workflow badge and adds version history notes.
Directory.Packages.propsIntroduces centrally-managed package versions.
Directory.Build.propsIntroduces shared build settings (net10.0, analyzers, CPM).
AGENTS.mdDocuments branching/release/workflow conventions for humans/agents.
.husky/task-runner.jsonAdjusts dotnet format invocation settings.
.husky/pre-commitNormalizes pre-commit hook formatting/line endings.
.gitignoreAdds .artifacts and corrects .user ignore pattern.
.github/workflows/test-pull-request.ymlAdds PR smoke-test workflow with required-check aggregator job.
.github/workflows/publish-release.ymlAdds central publish workflow (schedule/dispatch; opt-in push publishing).
.github/workflows/merge-bot-pull-request.ymlAdds branch-aware Dependabot merge-bot with app-token strategy.
.github/workflows/get-version-task.ymlAdds reusable NBGV version-resolution task.
.github/workflows/DependabotAutoMerge.ymlRemoves legacy Dependabot auto-merge workflow.
.github/workflows/BuildPublishPipeline.ymlRemoves legacy build/publish pipeline workflow.
.github/workflows/build-release-task.ymlAdds reusable orchestrator for build + publish + GitHub release.
.github/workflows/build-nugetlibrary-task.ymlAdds reusable NuGet library build/push task.
.github/workflows/build-datebadge-task.ymlAdds reusable date-badge workflow.
.github/dependabot.ymlUpdates Dependabot config to dual-target main and develop with documentation.
.github/copilot-instructions.mdAdds repository-specific Copilot guidance (style/AOT/testing).
.editorconfigDocuments analyzer relaxations and adds Husky hook line-ending rule.
Comments suppressed due to low confidence (1)

Utilities/FileEx.cs:333

  • RenameFile compares directories via originalDirectory.Equals(...), which will throw if either path has no directory component (GetDirectoryName returns null). After allowing relative paths, use string.Equals to handle nulls safely.
 // Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{

Comment threadUtilities/FileEx.cs
Comment on lines +287 to +300
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +387 to +400
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +428 to +430
// Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{
Comment threadUtilities/FileEx.cs
Comment on lines +1146 to +1148
string? directory = Path.GetDirectoryName(filePath);
string fileName = $"{timeStamp:yyyyMMddTHHmmss}_{Path.GetFileName(filePath)}";
return Path.Combine(directory, fileName);
return Path.Combine(directory!, fileName);
Comment threadUtilities/FileEx.cs
Comment on lines +110 to +114
fileName
);
await Task.Delay(Options.RetryWaitTime * 1000, cancellationToken)
.ConfigureAwait(false);
}
{
private readonly UtilitiesTests _fixture = fixture;

[Fact]
Assert.True(size > 0);
}

[Fact]
Assert.Contains("google", content, StringComparison.OrdinalIgnoreCase);
}

[Fact]
}
}

[Fact]
Assert.False(success);
}

[Fact]
@ptr727

Copy link
Copy Markdown
OwnerAuthor

Superseded by the release branch PR release/dualpublishmain, which resolves the inherent old→new merge conflicts (develop wins + max dependency versions) so CI and Copilot can run on a conflict-free PR.

Sign up for freeto 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.

3 participants

@ptr727
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Release: two-phase dual-publish release model - #321

Closed
ptr727 wants to merge 31 commits into
mainfrom
develop
Closed

Release: two-phase dual-publish release model#321
ptr727 wants to merge 31 commits into
mainfrom
develop

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Summary

Release PR promoting the two-phase dual-publish release model from develop to main (squashed via #320).

On merge, this is the first main state with the new model: publish-release.yml becomes the sole publisher (weekly Monday 02:00 UTC + manual dispatch, both branches, idempotent), PRs smoke-test only, and a branch-aware Dependabot merge-bot replaces the legacy auto-merge. Also includes Central Package Management, AGENTS.md, documented analyzer relaxations for the strict template settings, and line-ending/husky-hook normalization.

See #320 for the full change description and Copilot review.

Maintainer follow-ups (after this merges)

  • Add CODEGEN_APP_CLIENT_ID / CODEGEN_APP_PRIVATE_KEY (GitHub App) to both Actions and Dependabot secret stores for the merge-bot.
  • Bind the Check pull request workflow status required check to the develop (squash-only) and main (merge-only) rulesets.
  • Leave PUBLISH_ON_MERGE unset for the two-phase default; trigger the first publish via publish-release.yml → Run workflow.

🤖 Generated with Claude Code

dependabotBotand others added 30 commits August 19, 2025 20:51
Bumps csharpier from 1.1.1 to 1.1.2
Bumps xunit.analyzers from 1.23.0 to 1.24.0
Bumps xunit.runner.visualstudio from 3.1.3 to 3.1.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.1.2
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
- dependency-name: xunit.analyzers
dependency-version: 1.24.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-0259308462
Bump the nuget-deps group with 3 updates
Bumps xunit.runner.visualstudio from 3.1.4 to 3.1.5
---
updated-dependencies:
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…evelop/nuget-deps-6aadeae1b1
Bump the nuget-deps group with 1 update
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-39349b7924
Bump csharpier from 1.1.2 to 1.2.1
---
updated-dependencies:
- dependency-name: Serilog.Sinks.Console
dependency-version: 6.1.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…nuget-deps-602f419b37
Bump Serilog.Sinks.Console from 6.0.0 to 6.1.1
Bumps csharpier from 1.2.1 to 1.2.3
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.3
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-1689e99d0a
Bump the nuget-deps group with 1 update
Bumps the actions-deps group with 2 updates in the / directory: [actions/setup-dotnet](https://github.com/actions/setup-dotnet) and [actions/checkout](https://github.com/actions/checkout).
Updates `actions/setup-dotnet` from 4 to 5
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](actions/setup-dotnet@v4...v5)
Updates `actions/checkout` from 5 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)
---
updated-dependencies:
- dependency-name: actions/setup-dotnet
dependency-version: '5'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
- dependency-name: actions/checkout
dependency-version: '6'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps csharpier from 1.2.3 to 1.2.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-133b2bc611
Bump the nuget-deps group with 1 update
Bumps csharpier from 1.2.4 to 1.2.5
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-262ca43251
Bump the nuget-deps group with 1 update
* Initial plan
* Add using statement and simplify CallerMemberName attributes
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Make HttpClient timeout configurable via TimeoutSeconds property
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Initial plan
* Replace redundant ToString() with string interpolation in FileExAsyncTests
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Replace explicit ToString() calls with string interpolation
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
…304)
Bumps the actions-deps group with 1 update: [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata).
Updates `dependabot/fetch-metadata` from 2 to 3
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](dependabot/fetch-metadata@v2...v3)
---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
dependency-version: '3'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Convert to two-phase dual-publish release model
Replace publish-on-push with the ProjectTemplate/LanguageTags two-phase
model: PRs smoke-test only, and publish-release.yml publishes both branches
on a weekly schedule (Mon 02:00 UTC) or manual dispatch, with idempotent
no-op republish. Adopt the reusable workflow set (get-version,
build-nugetlibrary, build-release, build-datebadge), a branch-aware
Dependabot merge-bot, Central Package Management, and an AGENTS.md tracking
the template. NuGet.org-only (drop GitHub Packages); no Docker/exe/PyPI/codegen.
Reconcile the template's strict analyzers (AnalysisMode All +
TreatWarningsAsErrors) with the brownfield library by relaxing specific
rules in .editorconfig and IL3058 via NoWarn, all documented.
* Normalize line endings to .editorconfig; fix husky hook
Convert the workflow YAML, dependabot.yml, and AGENTS.md (added LF) to CRLF
per .editorconfig, and make .husky/pre-commit LF + executable so its shebang
execs on Linux/WSL. Add an .editorconfig rule pinning the hook to LF.
* Quote "$GITHUB_OUTPUT" in date-badge task
CopilotAI review requested due to automatic review settings June 5, 2026 01:28

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Promotes the repository to the two-phase dual-publish release model (PRs smoke-test only; publishing centralized in publish-release.yml), while also modernizing the .NET solution to .NET 10/AOT and aligning build/test/package management with the template conventions for easier future upstream syncing.

Changes:

  • Replaces the legacy publish-on-push pipeline with reusable workflow tasks + branch-aware scheduled/manual publishing and a Dependabot merge-bot.
  • Introduces Central Package Management (Directory.Build.props / Directory.Packages.props) and normalizes solution/repo metadata (.slnx, AGENTS.md, .editorconfig).
  • Modernizes the Utilities library (AOT config, async APIs, improved XML docs) and expands xUnit coverage with new test files.

Reviewed changes

Copilot reviewed 45 out of 47 changed files in this pull request and generated 22 comments.

Show a summary per file
FileDescription
version.jsonBumps base version for NBGV-managed releases.
UtilitiesTests/UtilitiesTests.csprojMoves test deps to Central Package Management and inherits net10.0 from props.
UtilitiesTests/UtilitiesTests.csCleans up usings to rely on implicit usings.
UtilitiesTests/StringHistoryTests.csAdds coverage for StringHistory behavior.
UtilitiesTests/StringCompressionTests.csCleans up usings.
UtilitiesTests/StringCompressionAsyncTests.csAdds async compression/decompression test coverage.
UtilitiesTests/FileExAsyncTests.csAdds async FileEx API coverage.
UtilitiesTests/ExtensionsTests.csAdds coverage for compression/logger extension methods.
UtilitiesTests/DownloadTests.csCleans up usings.
UtilitiesTests/DownloadAsyncTests.csAdds async Download API tests.
UtilitiesTests/ConsoleTests.csReplaces placeholder test with ConsoleEx coverage.
Utilities/Utilities.csproj.userRemoves user-specific Visual Studio metadata from repo.
Utilities/Utilities.csprojEnables AOT-related properties, XML docs generation, and Husky bootstrapping target.
Utilities/StringHistory.csAdds XML docs, null checking, and refactors ToString() implementation.
Utilities/StringCompression.csAdds XML docs, compression level support, and async APIs with cancellation.
Utilities/ProcessEx.csRemoves legacy process wrapper API.
Utilities/LogOptions.csAdds XML documentation to global logger config.
Utilities/Format.csAdds XML docs and refactors byte-format logic.
Utilities/FileExOptions.csAdds XML docs and clarifies option semantics.
Utilities/FileEx.csAdds async variants, improves XML docs, refactors logging helpers, and adds new helpers.
Utilities/Extensions.csMigrates to C# extension blocks; adds compression + logger helpers with caller info.
Utilities/Download.csAdds async APIs, shared HttpClient via Lazy<>, and improves header-only requests.
Utilities/ConsoleEx.csAdds XML docs and improves null handling.
Utilities/CommandLineEx.csAdds XML docs and tweaks argument splitting behavior.
Utilities.slnxReplaces .sln with .slnx including solution items/workflow files.
Utilities.slnRemoves legacy Visual Studio solution file.
Sandbox/Sandbox.csprojAligns sandbox project with net10/AOT + central package mgmt.
Sandbox/Program.csAdjusts assembly base directory logic.
README.mdUpdates workflow badge and adds version history notes.
Directory.Packages.propsIntroduces centrally-managed package versions.
Directory.Build.propsIntroduces shared build settings (net10.0, analyzers, CPM).
AGENTS.mdDocuments branching/release/workflow conventions for humans/agents.
.husky/task-runner.jsonAdjusts dotnet format invocation settings.
.husky/pre-commitNormalizes pre-commit hook formatting/line endings.
.gitignoreAdds .artifacts and corrects .user ignore pattern.
.github/workflows/test-pull-request.ymlAdds PR smoke-test workflow with required-check aggregator job.
.github/workflows/publish-release.ymlAdds central publish workflow (schedule/dispatch; opt-in push publishing).
.github/workflows/merge-bot-pull-request.ymlAdds branch-aware Dependabot merge-bot with app-token strategy.
.github/workflows/get-version-task.ymlAdds reusable NBGV version-resolution task.
.github/workflows/DependabotAutoMerge.ymlRemoves legacy Dependabot auto-merge workflow.
.github/workflows/BuildPublishPipeline.ymlRemoves legacy build/publish pipeline workflow.
.github/workflows/build-release-task.ymlAdds reusable orchestrator for build + publish + GitHub release.
.github/workflows/build-nugetlibrary-task.ymlAdds reusable NuGet library build/push task.
.github/workflows/build-datebadge-task.ymlAdds reusable date-badge workflow.
.github/dependabot.ymlUpdates Dependabot config to dual-target main and develop with documentation.
.github/copilot-instructions.mdAdds repository-specific Copilot guidance (style/AOT/testing).
.editorconfigDocuments analyzer relaxations and adds Husky hook line-ending rule.
Comments suppressed due to low confidence (1)

Utilities/FileEx.cs:333

  • RenameFile compares directories via originalDirectory.Equals(...), which will throw if either path has no directory component (GetDirectoryName returns null). After allowing relative paths, use string.Equals to handle nulls safely.
 // Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{

Comment threadUtilities/FileEx.cs
Comment on lines +287 to +300
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +387 to +400
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +428 to +430
// Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{
Comment threadUtilities/FileEx.cs
Comment on lines +1146 to +1148
string? directory = Path.GetDirectoryName(filePath);
string fileName = $"{timeStamp:yyyyMMddTHHmmss}_{Path.GetFileName(filePath)}";
return Path.Combine(directory, fileName);
return Path.Combine(directory!, fileName);
Comment threadUtilities/FileEx.cs
Comment on lines +110 to +114
fileName
);
await Task.Delay(Options.RetryWaitTime * 1000, cancellationToken)
.ConfigureAwait(false);
}
{
private readonly UtilitiesTests _fixture = fixture;

[Fact]
Assert.True(size > 0);
}

[Fact]
Assert.Contains("google", content, StringComparison.OrdinalIgnoreCase);
}

[Fact]
}
}

[Fact]
Assert.False(success);
}

[Fact]
@ptr727

Copy link
Copy Markdown
OwnerAuthor

Superseded by the release branch PR release/dualpublishmain, which resolves the inherent old→new merge conflicts (develop wins + max dependency versions) so CI and Copilot can run on a conflict-free PR.

Sign up for freeto 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.

3 participants

@ptr727
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Release: two-phase dual-publish release model - #321

Closed
ptr727 wants to merge 31 commits into
mainfrom
develop
Closed

Release: two-phase dual-publish release model#321
ptr727 wants to merge 31 commits into
mainfrom
develop

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Summary

Release PR promoting the two-phase dual-publish release model from develop to main (squashed via #320).

On merge, this is the first main state with the new model: publish-release.yml becomes the sole publisher (weekly Monday 02:00 UTC + manual dispatch, both branches, idempotent), PRs smoke-test only, and a branch-aware Dependabot merge-bot replaces the legacy auto-merge. Also includes Central Package Management, AGENTS.md, documented analyzer relaxations for the strict template settings, and line-ending/husky-hook normalization.

See #320 for the full change description and Copilot review.

Maintainer follow-ups (after this merges)

  • Add CODEGEN_APP_CLIENT_ID / CODEGEN_APP_PRIVATE_KEY (GitHub App) to both Actions and Dependabot secret stores for the merge-bot.
  • Bind the Check pull request workflow status required check to the develop (squash-only) and main (merge-only) rulesets.
  • Leave PUBLISH_ON_MERGE unset for the two-phase default; trigger the first publish via publish-release.yml → Run workflow.

🤖 Generated with Claude Code

dependabotBotand others added 30 commits August 19, 2025 20:51
Bumps csharpier from 1.1.1 to 1.1.2
Bumps xunit.analyzers from 1.23.0 to 1.24.0
Bumps xunit.runner.visualstudio from 3.1.3 to 3.1.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.1.2
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
- dependency-name: xunit.analyzers
dependency-version: 1.24.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-0259308462
Bump the nuget-deps group with 3 updates
Bumps xunit.runner.visualstudio from 3.1.4 to 3.1.5
---
updated-dependencies:
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…evelop/nuget-deps-6aadeae1b1
Bump the nuget-deps group with 1 update
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-39349b7924
Bump csharpier from 1.1.2 to 1.2.1
---
updated-dependencies:
- dependency-name: Serilog.Sinks.Console
dependency-version: 6.1.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…nuget-deps-602f419b37
Bump Serilog.Sinks.Console from 6.0.0 to 6.1.1
Bumps csharpier from 1.2.1 to 1.2.3
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.3
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-1689e99d0a
Bump the nuget-deps group with 1 update
Bumps the actions-deps group with 2 updates in the / directory: [actions/setup-dotnet](https://github.com/actions/setup-dotnet) and [actions/checkout](https://github.com/actions/checkout).
Updates `actions/setup-dotnet` from 4 to 5
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](actions/setup-dotnet@v4...v5)
Updates `actions/checkout` from 5 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)
---
updated-dependencies:
- dependency-name: actions/setup-dotnet
dependency-version: '5'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
- dependency-name: actions/checkout
dependency-version: '6'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps csharpier from 1.2.3 to 1.2.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-133b2bc611
Bump the nuget-deps group with 1 update
Bumps csharpier from 1.2.4 to 1.2.5
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-262ca43251
Bump the nuget-deps group with 1 update
* Initial plan
* Add using statement and simplify CallerMemberName attributes
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Make HttpClient timeout configurable via TimeoutSeconds property
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Initial plan
* Replace redundant ToString() with string interpolation in FileExAsyncTests
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Replace explicit ToString() calls with string interpolation
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
…304)
Bumps the actions-deps group with 1 update: [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata).
Updates `dependabot/fetch-metadata` from 2 to 3
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](dependabot/fetch-metadata@v2...v3)
---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
dependency-version: '3'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Convert to two-phase dual-publish release model
Replace publish-on-push with the ProjectTemplate/LanguageTags two-phase
model: PRs smoke-test only, and publish-release.yml publishes both branches
on a weekly schedule (Mon 02:00 UTC) or manual dispatch, with idempotent
no-op republish. Adopt the reusable workflow set (get-version,
build-nugetlibrary, build-release, build-datebadge), a branch-aware
Dependabot merge-bot, Central Package Management, and an AGENTS.md tracking
the template. NuGet.org-only (drop GitHub Packages); no Docker/exe/PyPI/codegen.
Reconcile the template's strict analyzers (AnalysisMode All +
TreatWarningsAsErrors) with the brownfield library by relaxing specific
rules in .editorconfig and IL3058 via NoWarn, all documented.
* Normalize line endings to .editorconfig; fix husky hook
Convert the workflow YAML, dependabot.yml, and AGENTS.md (added LF) to CRLF
per .editorconfig, and make .husky/pre-commit LF + executable so its shebang
execs on Linux/WSL. Add an .editorconfig rule pinning the hook to LF.
* Quote "$GITHUB_OUTPUT" in date-badge task
CopilotAI review requested due to automatic review settings June 5, 2026 01:28

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Promotes the repository to the two-phase dual-publish release model (PRs smoke-test only; publishing centralized in publish-release.yml), while also modernizing the .NET solution to .NET 10/AOT and aligning build/test/package management with the template conventions for easier future upstream syncing.

Changes:

  • Replaces the legacy publish-on-push pipeline with reusable workflow tasks + branch-aware scheduled/manual publishing and a Dependabot merge-bot.
  • Introduces Central Package Management (Directory.Build.props / Directory.Packages.props) and normalizes solution/repo metadata (.slnx, AGENTS.md, .editorconfig).
  • Modernizes the Utilities library (AOT config, async APIs, improved XML docs) and expands xUnit coverage with new test files.

Reviewed changes

Copilot reviewed 45 out of 47 changed files in this pull request and generated 22 comments.

Show a summary per file
FileDescription
version.jsonBumps base version for NBGV-managed releases.
UtilitiesTests/UtilitiesTests.csprojMoves test deps to Central Package Management and inherits net10.0 from props.
UtilitiesTests/UtilitiesTests.csCleans up usings to rely on implicit usings.
UtilitiesTests/StringHistoryTests.csAdds coverage for StringHistory behavior.
UtilitiesTests/StringCompressionTests.csCleans up usings.
UtilitiesTests/StringCompressionAsyncTests.csAdds async compression/decompression test coverage.
UtilitiesTests/FileExAsyncTests.csAdds async FileEx API coverage.
UtilitiesTests/ExtensionsTests.csAdds coverage for compression/logger extension methods.
UtilitiesTests/DownloadTests.csCleans up usings.
UtilitiesTests/DownloadAsyncTests.csAdds async Download API tests.
UtilitiesTests/ConsoleTests.csReplaces placeholder test with ConsoleEx coverage.
Utilities/Utilities.csproj.userRemoves user-specific Visual Studio metadata from repo.
Utilities/Utilities.csprojEnables AOT-related properties, XML docs generation, and Husky bootstrapping target.
Utilities/StringHistory.csAdds XML docs, null checking, and refactors ToString() implementation.
Utilities/StringCompression.csAdds XML docs, compression level support, and async APIs with cancellation.
Utilities/ProcessEx.csRemoves legacy process wrapper API.
Utilities/LogOptions.csAdds XML documentation to global logger config.
Utilities/Format.csAdds XML docs and refactors byte-format logic.
Utilities/FileExOptions.csAdds XML docs and clarifies option semantics.
Utilities/FileEx.csAdds async variants, improves XML docs, refactors logging helpers, and adds new helpers.
Utilities/Extensions.csMigrates to C# extension blocks; adds compression + logger helpers with caller info.
Utilities/Download.csAdds async APIs, shared HttpClient via Lazy<>, and improves header-only requests.
Utilities/ConsoleEx.csAdds XML docs and improves null handling.
Utilities/CommandLineEx.csAdds XML docs and tweaks argument splitting behavior.
Utilities.slnxReplaces .sln with .slnx including solution items/workflow files.
Utilities.slnRemoves legacy Visual Studio solution file.
Sandbox/Sandbox.csprojAligns sandbox project with net10/AOT + central package mgmt.
Sandbox/Program.csAdjusts assembly base directory logic.
README.mdUpdates workflow badge and adds version history notes.
Directory.Packages.propsIntroduces centrally-managed package versions.
Directory.Build.propsIntroduces shared build settings (net10.0, analyzers, CPM).
AGENTS.mdDocuments branching/release/workflow conventions for humans/agents.
.husky/task-runner.jsonAdjusts dotnet format invocation settings.
.husky/pre-commitNormalizes pre-commit hook formatting/line endings.
.gitignoreAdds .artifacts and corrects .user ignore pattern.
.github/workflows/test-pull-request.ymlAdds PR smoke-test workflow with required-check aggregator job.
.github/workflows/publish-release.ymlAdds central publish workflow (schedule/dispatch; opt-in push publishing).
.github/workflows/merge-bot-pull-request.ymlAdds branch-aware Dependabot merge-bot with app-token strategy.
.github/workflows/get-version-task.ymlAdds reusable NBGV version-resolution task.
.github/workflows/DependabotAutoMerge.ymlRemoves legacy Dependabot auto-merge workflow.
.github/workflows/BuildPublishPipeline.ymlRemoves legacy build/publish pipeline workflow.
.github/workflows/build-release-task.ymlAdds reusable orchestrator for build + publish + GitHub release.
.github/workflows/build-nugetlibrary-task.ymlAdds reusable NuGet library build/push task.
.github/workflows/build-datebadge-task.ymlAdds reusable date-badge workflow.
.github/dependabot.ymlUpdates Dependabot config to dual-target main and develop with documentation.
.github/copilot-instructions.mdAdds repository-specific Copilot guidance (style/AOT/testing).
.editorconfigDocuments analyzer relaxations and adds Husky hook line-ending rule.
Comments suppressed due to low confidence (1)

Utilities/FileEx.cs:333

  • RenameFile compares directories via originalDirectory.Equals(...), which will throw if either path has no directory component (GetDirectoryName returns null). After allowing relative paths, use string.Equals to handle nulls safely.
 // Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{

Comment threadUtilities/FileEx.cs
Comment on lines +287 to +300
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +387 to +400
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +428 to +430
// Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{
Comment threadUtilities/FileEx.cs
Comment on lines +1146 to +1148
string? directory = Path.GetDirectoryName(filePath);
string fileName = $"{timeStamp:yyyyMMddTHHmmss}_{Path.GetFileName(filePath)}";
return Path.Combine(directory, fileName);
return Path.Combine(directory!, fileName);
Comment threadUtilities/FileEx.cs
Comment on lines +110 to +114
fileName
);
await Task.Delay(Options.RetryWaitTime * 1000, cancellationToken)
.ConfigureAwait(false);
}
{
private readonly UtilitiesTests _fixture = fixture;

[Fact]
Assert.True(size > 0);
}

[Fact]
Assert.Contains("google", content, StringComparison.OrdinalIgnoreCase);
}

[Fact]
}
}

[Fact]
Assert.False(success);
}

[Fact]
@ptr727

Copy link
Copy Markdown
OwnerAuthor

Superseded by the release branch PR release/dualpublishmain, which resolves the inherent old→new merge conflicts (develop wins + max dependency versions) so CI and Copilot can run on a conflict-free PR.

Sign up for freeto 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.

3 participants

@ptr727
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Release: two-phase dual-publish release model - #321

Closed
ptr727 wants to merge 31 commits into
mainfrom
develop
Closed

Release: two-phase dual-publish release model#321
ptr727 wants to merge 31 commits into
mainfrom
develop

Conversation

@ptr727

Copy link
Copy Markdown
Owner

Summary

Release PR promoting the two-phase dual-publish release model from develop to main (squashed via #320).

On merge, this is the first main state with the new model: publish-release.yml becomes the sole publisher (weekly Monday 02:00 UTC + manual dispatch, both branches, idempotent), PRs smoke-test only, and a branch-aware Dependabot merge-bot replaces the legacy auto-merge. Also includes Central Package Management, AGENTS.md, documented analyzer relaxations for the strict template settings, and line-ending/husky-hook normalization.

See #320 for the full change description and Copilot review.

Maintainer follow-ups (after this merges)

  • Add CODEGEN_APP_CLIENT_ID / CODEGEN_APP_PRIVATE_KEY (GitHub App) to both Actions and Dependabot secret stores for the merge-bot.
  • Bind the Check pull request workflow status required check to the develop (squash-only) and main (merge-only) rulesets.
  • Leave PUBLISH_ON_MERGE unset for the two-phase default; trigger the first publish via publish-release.yml → Run workflow.

🤖 Generated with Claude Code

dependabotBotand others added 30 commits August 19, 2025 20:51
Bumps csharpier from 1.1.1 to 1.1.2
Bumps xunit.analyzers from 1.23.0 to 1.24.0
Bumps xunit.runner.visualstudio from 3.1.3 to 3.1.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.1.2
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
- dependency-name: xunit.analyzers
dependency-version: 1.24.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-0259308462
Bump the nuget-deps group with 3 updates
Bumps xunit.runner.visualstudio from 3.1.4 to 3.1.5
---
updated-dependencies:
- dependency-name: xunit.runner.visualstudio
dependency-version: 3.1.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…evelop/nuget-deps-6aadeae1b1
Bump the nuget-deps group with 1 update
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-39349b7924
Bump csharpier from 1.1.2 to 1.2.1
---
updated-dependencies:
- dependency-name: Serilog.Sinks.Console
dependency-version: 6.1.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…nuget-deps-602f419b37
Bump Serilog.Sinks.Console from 6.0.0 to 6.1.1
Bumps csharpier from 1.2.1 to 1.2.3
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.3
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-1689e99d0a
Bump the nuget-deps group with 1 update
Bumps the actions-deps group with 2 updates in the / directory: [actions/setup-dotnet](https://github.com/actions/setup-dotnet) and [actions/checkout](https://github.com/actions/checkout).
Updates `actions/setup-dotnet` from 4 to 5
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](actions/setup-dotnet@v4...v5)
Updates `actions/checkout` from 5 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)
---
updated-dependencies:
- dependency-name: actions/setup-dotnet
dependency-version: '5'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
- dependency-name: actions/checkout
dependency-version: '6'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps csharpier from 1.2.3 to 1.2.4
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-133b2bc611
Bump the nuget-deps group with 1 update
Bumps csharpier from 1.2.4 to 1.2.5
---
updated-dependencies:
- dependency-name: csharpier
dependency-version: 1.2.5
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: nuget-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
…op/nuget-deps-262ca43251
Bump the nuget-deps group with 1 update
* Initial plan
* Add using statement and simplify CallerMemberName attributes
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Make HttpClient timeout configurable via TimeoutSeconds property
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Initial plan
* Replace redundant ToString() with string interpolation in FileExAsyncTests
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan
* Replace explicit ToString() calls with string interpolation
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptr727 <2061579+ptr727@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
…304)
Bumps the actions-deps group with 1 update: [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata).
Updates `dependabot/fetch-metadata` from 2 to 3
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](dependabot/fetch-metadata@v2...v3)
---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
dependency-version: '3'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: actions-deps
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Convert to two-phase dual-publish release model
Replace publish-on-push with the ProjectTemplate/LanguageTags two-phase
model: PRs smoke-test only, and publish-release.yml publishes both branches
on a weekly schedule (Mon 02:00 UTC) or manual dispatch, with idempotent
no-op republish. Adopt the reusable workflow set (get-version,
build-nugetlibrary, build-release, build-datebadge), a branch-aware
Dependabot merge-bot, Central Package Management, and an AGENTS.md tracking
the template. NuGet.org-only (drop GitHub Packages); no Docker/exe/PyPI/codegen.
Reconcile the template's strict analyzers (AnalysisMode All +
TreatWarningsAsErrors) with the brownfield library by relaxing specific
rules in .editorconfig and IL3058 via NoWarn, all documented.
* Normalize line endings to .editorconfig; fix husky hook
Convert the workflow YAML, dependabot.yml, and AGENTS.md (added LF) to CRLF
per .editorconfig, and make .husky/pre-commit LF + executable so its shebang
execs on Linux/WSL. Add an .editorconfig rule pinning the hook to LF.
* Quote "$GITHUB_OUTPUT" in date-badge task
CopilotAI review requested due to automatic review settings June 5, 2026 01:28

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Promotes the repository to the two-phase dual-publish release model (PRs smoke-test only; publishing centralized in publish-release.yml), while also modernizing the .NET solution to .NET 10/AOT and aligning build/test/package management with the template conventions for easier future upstream syncing.

Changes:

  • Replaces the legacy publish-on-push pipeline with reusable workflow tasks + branch-aware scheduled/manual publishing and a Dependabot merge-bot.
  • Introduces Central Package Management (Directory.Build.props / Directory.Packages.props) and normalizes solution/repo metadata (.slnx, AGENTS.md, .editorconfig).
  • Modernizes the Utilities library (AOT config, async APIs, improved XML docs) and expands xUnit coverage with new test files.

Reviewed changes

Copilot reviewed 45 out of 47 changed files in this pull request and generated 22 comments.

Show a summary per file
FileDescription
version.jsonBumps base version for NBGV-managed releases.
UtilitiesTests/UtilitiesTests.csprojMoves test deps to Central Package Management and inherits net10.0 from props.
UtilitiesTests/UtilitiesTests.csCleans up usings to rely on implicit usings.
UtilitiesTests/StringHistoryTests.csAdds coverage for StringHistory behavior.
UtilitiesTests/StringCompressionTests.csCleans up usings.
UtilitiesTests/StringCompressionAsyncTests.csAdds async compression/decompression test coverage.
UtilitiesTests/FileExAsyncTests.csAdds async FileEx API coverage.
UtilitiesTests/ExtensionsTests.csAdds coverage for compression/logger extension methods.
UtilitiesTests/DownloadTests.csCleans up usings.
UtilitiesTests/DownloadAsyncTests.csAdds async Download API tests.
UtilitiesTests/ConsoleTests.csReplaces placeholder test with ConsoleEx coverage.
Utilities/Utilities.csproj.userRemoves user-specific Visual Studio metadata from repo.
Utilities/Utilities.csprojEnables AOT-related properties, XML docs generation, and Husky bootstrapping target.
Utilities/StringHistory.csAdds XML docs, null checking, and refactors ToString() implementation.
Utilities/StringCompression.csAdds XML docs, compression level support, and async APIs with cancellation.
Utilities/ProcessEx.csRemoves legacy process wrapper API.
Utilities/LogOptions.csAdds XML documentation to global logger config.
Utilities/Format.csAdds XML docs and refactors byte-format logic.
Utilities/FileExOptions.csAdds XML docs and clarifies option semantics.
Utilities/FileEx.csAdds async variants, improves XML docs, refactors logging helpers, and adds new helpers.
Utilities/Extensions.csMigrates to C# extension blocks; adds compression + logger helpers with caller info.
Utilities/Download.csAdds async APIs, shared HttpClient via Lazy<>, and improves header-only requests.
Utilities/ConsoleEx.csAdds XML docs and improves null handling.
Utilities/CommandLineEx.csAdds XML docs and tweaks argument splitting behavior.
Utilities.slnxReplaces .sln with .slnx including solution items/workflow files.
Utilities.slnRemoves legacy Visual Studio solution file.
Sandbox/Sandbox.csprojAligns sandbox project with net10/AOT + central package mgmt.
Sandbox/Program.csAdjusts assembly base directory logic.
README.mdUpdates workflow badge and adds version history notes.
Directory.Packages.propsIntroduces centrally-managed package versions.
Directory.Build.propsIntroduces shared build settings (net10.0, analyzers, CPM).
AGENTS.mdDocuments branching/release/workflow conventions for humans/agents.
.husky/task-runner.jsonAdjusts dotnet format invocation settings.
.husky/pre-commitNormalizes pre-commit hook formatting/line endings.
.gitignoreAdds .artifacts and corrects .user ignore pattern.
.github/workflows/test-pull-request.ymlAdds PR smoke-test workflow with required-check aggregator job.
.github/workflows/publish-release.ymlAdds central publish workflow (schedule/dispatch; opt-in push publishing).
.github/workflows/merge-bot-pull-request.ymlAdds branch-aware Dependabot merge-bot with app-token strategy.
.github/workflows/get-version-task.ymlAdds reusable NBGV version-resolution task.
.github/workflows/DependabotAutoMerge.ymlRemoves legacy Dependabot auto-merge workflow.
.github/workflows/BuildPublishPipeline.ymlRemoves legacy build/publish pipeline workflow.
.github/workflows/build-release-task.ymlAdds reusable orchestrator for build + publish + GitHub release.
.github/workflows/build-nugetlibrary-task.ymlAdds reusable NuGet library build/push task.
.github/workflows/build-datebadge-task.ymlAdds reusable date-badge workflow.
.github/dependabot.ymlUpdates Dependabot config to dual-target main and develop with documentation.
.github/copilot-instructions.mdAdds repository-specific Copilot guidance (style/AOT/testing).
.editorconfigDocuments analyzer relaxations and adds Husky hook line-ending rule.
Comments suppressed due to low confidence (1)

Utilities/FileEx.cs:333

  • RenameFile compares directories via originalDirectory.Equals(...), which will throw if either path has no directory component (GetDirectoryName returns null). After allowing relative paths, use string.Equals to handle nulls safely.
 // Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{

Comment threadUtilities/FileEx.cs
Comment on lines +287 to +300
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +387 to +400
if (
string.IsNullOrEmpty(originalDirectory)
|| string.IsNullOrEmpty(originalFile)
|| string.IsNullOrEmpty(newDirectory)
|| string.IsNullOrEmpty(newFile)
)
{
LogOptions.Logger.Error(
"Renaming file failed due to invalid path(s) : {OriginalName} to {NewName}",
originalName,
newName
);
return false;
}
Comment threadUtilities/FileEx.cs
Comment on lines +428 to +430
// Retry
if (originalDirectory.Equals(newDirectory, StringComparison.OrdinalIgnoreCase))
{
Comment threadUtilities/FileEx.cs
Comment on lines +1146 to +1148
string? directory = Path.GetDirectoryName(filePath);
string fileName = $"{timeStamp:yyyyMMddTHHmmss}_{Path.GetFileName(filePath)}";
return Path.Combine(directory, fileName);
return Path.Combine(directory!, fileName);
Comment threadUtilities/FileEx.cs
Comment on lines +110 to +114
fileName
);
await Task.Delay(Options.RetryWaitTime * 1000, cancellationToken)
.ConfigureAwait(false);
}
{
private readonly UtilitiesTests _fixture = fixture;

[Fact]
Assert.True(size > 0);
}

[Fact]
Assert.Contains("google", content, StringComparison.OrdinalIgnoreCase);
}

[Fact]
}
}

[Fact]
Assert.False(success);
}

[Fact]
@ptr727

Copy link
Copy Markdown
OwnerAuthor

Superseded by the release branch PR release/dualpublishmain, which resolves the inherent old→new merge conflicts (develop wins + max dependency versions) so CI and Copilot can run on a conflict-free PR.

Sign up for freeto 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.

3 participants

@ptr727