fix: preserve leading zeros in SwampVersion calver time component#440
Merged
fix: preserve leading zeros in SwampVersion calver time component#440
Conversation
SwampVersion.create() used parseInt() to parse version segments, which strips leading zeros. For builds between midnight and ~09:59:59, the HHMMSS time component (e.g. 003901) lost its leading zeros, causing toString() to return "20260224.3901.0" instead of "20260224.003901.0". This broke .swamp.yaml version round-tripping and failed UAT validation. The fix stores the original string segments alongside the parsed integer values, using the raw strings for toString() while keeping integers for compareTo/equals. This preserves exact round-tripping for all version formats (both semver and calver). Fixes #439 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Review Summary
This PR correctly fixes the leading zeros issue in SwampVersion calver formatting. The implementation is clean and follows project conventions.
✅ No Blocking Issues
Code Quality Assessment
TypeScript Strict Mode: ✅ Compliant
- No
anytypes - Proper type annotations with
readonlymodifiers - Private constructor maintained for immutability
Code Style (CLAUDE.md): ✅ Compliant
- Named exports used (
export class SwampVersion) - AGPLv3 copyright header present
- Passes linting requirements per PR description
Domain-Driven Design: ✅ Well-designed
SwampVersionis correctly implemented as a Value Object- The
rawVersionfield is appropriately private - it's an implementation detail for roundtrip fidelity - Comparison operations still use integer values, which is semantically correct since
"003901"and"3901"represent the same numeric value - Immutability preserved with
readonlymodifier
Test Coverage: ✅ Good
- Two regression tests added covering both cases (with and without sha suffix)
- Tests verify both the string output and numeric parsing
- Test file properly co-located with source (
swamp_version_test.ts)
Security: ✅ No concerns
- Simple value object change with no security implications
Implementation Notes
The approach of storing rawVersion from regex match groups rather than reconstructing from integers is elegant - it correctly strips the suffix while preserving leading zeros in the version segments. This maintains exact roundtrip fidelity without breaking comparison semantics.
LGTM! 🎉
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #439
SwampVersion.create()usesparseInt()to parse calver version segments into integers for comparison. However,toString()was reconstructing the version string from those integers, which strips leading zeros. This is a problem for builds between midnight and ~09:59:59 UTC, where theHHMMSStime component has leading zeros (e.g.003901).Example of the bug:
This caused
.swamp.yamlversion round-tripping to fail — the version written back after parsing didn't match the original, breaking UAT validation for early-morning builds.Fix
Store the original string segments (
rawVersion) alongside the parsed integer values.toString()now returns the preserved raw string instead of reconstructing from integers. The integer fields (major,minor,patch) remain unchanged and continue to be used forcompareTo,equals,isNewerThan, andisOlderThan.This approach preserves exact round-tripping for all version formats:
"20260224.003901.0"→toString()→"20260224.003901.0""1.2.3"→toString()→"1.2.3""20260224.003901.0-sha.abc123"→toString()→"20260224.003901.0"(suffix correctly stripped, zeros preserved)Test plan
create("20260224.003901.0").toString()returns"20260224.003901.0"SwampVersiontests pass (includingcreate("1.2.3").toString() === "1.2.3")deno check,deno lint,deno fmtall clean🤖 Generated with Claude Code