| name | senparc-version-updater |
| description | Update version metadata for Senparc-prefixed .NET projects. Use when Codex needs to update package versions in .csproj files (preferring .net10+ variants), propagate changed shared .props imports to all importing projects, summarize project changes since the merge-base against master/main, add standardized Chinese changelog headers to changed .cs files, append PackageReleaseNotes entries, and recursively bump versions for referencing projects. |
Senparc Version Updater
Inputs
Provide:
- Repository root path.
- Target project path (a
.csproj file or the project directory).
- Author name for change records (default
Senparc).
Run Scanner First
Run:
python3 scripts/senparc_version_scan.py --root <repo-root> --project <project-path>
Use the output JSON as the source of truth for:
- The selected primary
.csproj to edit.
- Changed files in the current update scope (
comparison_base..HEAD plus uncommitted) across the entire repository, not just the primary project directory.
- Changed
.cs files that must receive header updates (repository-wide).
- Changed
.props files and all projects that import them directly or through another .props file (changed_props_importers).
.csproj files mapped from changed .cs files or changed .props imports (changed_csprojs) that must receive direct project updates.
- Direct update roots (
dependency_roots) and recursive dependent .csproj files that need passive version bumps.
- Comparison baseline metadata (
master/main branch ref and merge-base commit).
Special skip rules for header updates:
- Never add header comments to
*.Generated.cs.
- If a
*.Generated.cs change only updates timestamp-like text after regeneration and has no real content change, do not treat it as a changed file.
- Never add header comments to files under unit test projects (directory names such as
Tests, *.Tests, or *Tests).
- Never add header comments to files under
MultipleDatabase/ directory.
Commit Baseline Rule (Strict)
Before any version decision, resolve comparison baseline in this priority:
origin/master
origin/main
master
main
Then:
- Compute
merge-base(HEAD, baseline-branch) as comparison_base.
- Treat all commits in
comparison_base..HEAD as this update's commit set.
- Include uncommitted workspace changes in the same update scope.
- If no
master/main branch can be resolved or merge-base fails, stop and report error (do not fallback to other windows).
Apply Workflow
1) Select The .csproj To Edit
Follow this selection rule per project directory:
- If multiple
.csproj files exist, select .net10.csproj or the highest .netXX.csproj above 10.
- If no filename-level
.net10+ candidate exists, select the file with the highest TargetFramework major version.
- If only one
.csproj exists, use it directly.
Use the scanner's primary_csproj and dependent_csprojs to avoid inconsistent manual selection.
2) Derive New Version From Real Changes
Treat the time window as:
- Start: scanner output
comparison_base.commit (merge-base vs master/main).
- End: current workspace state (
HEAD plus uncommitted files).
Summarize all project updates in this window and decide bump type:
major: breaking API/behavior or incompatible contract change.
minor: new non-breaking features/public capability expansion.
patch: bug fix/refactor/test/docs/passive dependency bump.
If current version contains prerelease suffix (-preview.N), preserve prerelease channel and increment its number while applying the major/minor/patch base bump.
For commits that are still unmerged into master/main (same comparison_base..HEAD window), bump version at most once. Subsequent updates in the same unmerged window must reuse the same version and only append/merge release notes.
Version must be monotonic non-decreasing per project: never lower <Version> than the pre-update value. In the same unmerged window, reusing the same version is allowed when only merging release notes.
See versioning-policy.md.
3) Update Header Logs In All Changed .cs Files
For every file in changed_cs_files:
- Ensure a top-of-file changelog block exists.
- Use the exact format in header-template.md.
- Replace
文件名 with actual filename.
- Set
文件功能描述 once and keep it stable afterward.
- Set
创建标识 date to file creation date (creation_date_yyyymmdd from scanner, fallback to today).
- Append one new pair for current change:
修改标识:<author> - YYYYMMDD
修改描述:v<new-version> <summary>
- Keep exactly one blank line between modification groups (no extra blank lines).
- Skip files matched by the special skip rules above (
*.Generated.cs, unit test project files, and MultipleDatabase/ directory files).
If the file already has the block, keep historical entries and append only one new modification group.
Always skip *.Generated.cs for header insertion.
changed_cs_files is generated from the repository-wide comparison window, so this step must not filter to the primary project directory.
4) Resolve Changed .props Imports And Update All Changed Projects
For every changed .props file:
- Resolve explicit
<Import Project="...props" /> paths, including $(MSBuildThisFileDirectory) and $(MSBuildProjectDirectory).
- Follow
.props -> .props imports transitively until all importing .csproj files are found.
- Treat every importing project as directly changed, even if none of its own
.cs files changed.
- Add these projects to
changed_csprojs, dependency_roots, and changed_csproj_to_props_files.
- A changed
.props file does not receive a C# header block; its functional effect must be recorded in every importing project's <PackageReleaseNotes>.
For all projects in changed_csprojs (from changed .cs files or changed .props imports):
- Ensure project version metadata and release notes are updated for this window.
- For the same unmerged window (
comparison_base..HEAD), version can only bump once per project.
- If new commits are added before merge, merge details into the same version's release-note block instead of creating a new version entry.
- If any
.cs file is edited in this run (including header-only edits), its mapped project in changed_csprojs must receive a release-note merge/update in the current version block (no silent skip).
- If a shared
.props file changes package/version properties, describe the resulting dependency or compatibility change functionally in each importing project; do not use generic process text.
5) Append <PackageReleaseNotes> In Selected .csproj
In every .csproj in changed_csprojs (the selected primary must also satisfy Step 4 when affected):
- Append new lines to existing
<PackageReleaseNotes> content.
- Keep the same leading spaces as the previous line.
- Do not insert blank lines inside
<PackageReleaseNotes> (including between entries and detail lines).
- Use this structure:
[YYYY-MM-DD] vX.Y.Z <one-line summary>
1、<detail>
2、<detail>
- Include all key updates found in Step 2.
- Within the same unmerged
comparison_base..HEAD window, do not create another version bump entry; merge new details into the same vX.Y.Z release-note block.
summary/detail must describe project functional changes (feature, behavior, compatibility, bug fix, UI/UX, dependency adaptation).
- Do not write process-tracking text in release notes, including but not limited to:
Repository baseline sync, sync window, comparison_base..HEAD, or similar window/baseline markers.
<PackageReleaseNotes> must be located after <Version> in the .csproj file.
<PackageReleaseNotes> does not need to be immediately adjacent to <Version>. If it is already after <Version>, keep its current position (manual placement may exist).
- If
<PackageReleaseNotes> appears before <Version>, move <PackageReleaseNotes> to any valid location after <Version> while preserving indentation/content.
<Version> must be located after <TargetFramework> or <TargetFrameworks> in the .csproj file.
<Version> does not need to be immediately adjacent to <TargetFramework>/<TargetFrameworks>. If it is already after framework tags, keep its current position.
- If
<Version> appears before <TargetFramework>/<TargetFrameworks>, move <Version> to any valid location after framework tags while preserving indentation/content.
If <PackageReleaseNotes> does not exist, create it under the first <PropertyGroup> and match surrounding indentation.
6) Propagate Version Bumps To Referencing Projects
For all projects in dependent_csprojs, starting from every project in dependency_roots:
- Update version with passive bump policy (
patch unless explicit override).
- Append a passive release note item:
[YYYY-MM-DD] vX.Y.Z Dependency update from <project-name> to <source-version>
- If a dependent project lacks
<Version>, create it under the first <PropertyGroup> before writing release notes.
- Continue recursively for projects referencing those projects.
Process the union of dependency layers from all direct roots, from nearest dependents to farthest dependents, and avoid cycles with a visited set. Do not calculate dependents from an unrelated primary_csproj when other projects are the actual changed roots.
7) Validate Before Finish
Validate:
- Every eligible file in
changed_cs_files (after applying special skip rules) contains a valid changelog block.
- Every changed
.props file is mapped to all direct and transitive importing projects in changed_props_importers.
- Every
.csproj in changed_csprojs (including .props importers) has updated version/release notes for current window.
- All recursive dependents from every
dependency_roots project are covered.
- In every edited
.csproj, <Version> is located after <TargetFramework> or <TargetFrameworks>.
- In every edited
.csproj, <PackageReleaseNotes> is located after <Version>.
- In every edited
.csproj, lines appended to <PackageReleaseNotes> use the same indentation as the previous note line.
- In every edited
.csproj, <PackageReleaseNotes> contains no blank line.
- In every edited
.csproj, resulting <Version> is not lower than its pre-update <Version>.
- All commits in
comparison_base..HEAD are reflected by updated files/projects in this workflow.
- For every edited
.cs file in this run, its mapped .csproj has a release-note merge/update in current window version block.
- Optional: run project build/tests before commit.
Suggested Command Sequence
python3 scripts/senparc_version_scan.py --root <repo-root> --project <project-path> > /tmp/senparc-version-scan.json
jq -r '.comparison_base.branch_ref, .comparison_base.commit, .comparison_range' /tmp/senparc-version-scan.json
jq -r '.changed_cs_files[].path' /tmp/senparc-version-scan.json
jq -r '.changed_cs_files_in_primary_project[].path' /tmp/senparc-version-scan.json
jq -r '.changed_csprojs[]' /tmp/senparc-version-scan.json
jq -r '.changed_csproj_to_cs_files | to_entries[] | .key as $p | .value[] | "\($p)\t\(.path)"' /tmp/senparc-version-scan.json
jq -r '.changed_props_importers | to_entries[] | .key as $props | .value[] | "\($props)\t\(.)"' /tmp/senparc-version-scan.json
jq -r '.dependency_roots[]' /tmp/senparc-version-scan.json
jq -r '.dependent_csprojs[]' /tmp/senparc-version-scan.json
jq -r '.commit_summaries[] | "\(.date) \(.commit) \(.message)"' /tmp/senparc-version-scan.json