Skip to content

Conversation

@ksylvan
Copy link
Collaborator

@ksylvan ksylvan commented Jan 4, 2026

ChangeLog Generation stability

Summary

This pull request enhances the robustness of date parsing in the changelog generation tool and fixes a logic issue in version content generation to ensure PR syncing still happens correctly after the --process-prs phase that incorporated the incoming ChangeLog snippets into the repo's CHANGELOG.md durring CI/CD.

After this change, doing this produces an identical change log:

generate_changelog --ai-summarize > CHANGELOG.md

Files Changed

  • cmd/generate_changelog/internal/cache/cache.go: Modified the GetVersions() function to support multiple date formats during parsing, improving compatibility with SQLite-stored dates.
  • cmd/generate_changelog/internal/changelog/generator.go: Updated the generateRawVersionContent() function to avoid early returns when PR numbers are available, ensuring they are outputted.

Code Changes

cmd/generate_changelog/internal/cache/cache.go

The key change is in the date parsing logic within GetVersions():

// Before: Only tried RFC3339Nano and RFC3339
v.Date, err = time.Parse(time.RFC3339Nano, dateStr.String)
if err != nil {
    v.Date, err = time.Parse(time.RFC3339, dateStr.String)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Error parsing date '%s' for version '%s': %v. Expected format: RFC3339 or RFC3339Nano.\n", dateStr.String, v.Name, err)
    }
}

// After: Tries multiple formats in a loop
dateFormats := []string{
    "2006-01-02 15:04:05-07:00",   // SQLite DATETIME format
    "2006-01-02 15:04:05.999999999-07:00", // SQLite with fractional seconds
    time.RFC3339Nano,
    time.RFC3339,
}
var parseErr error
for _, format := range dateFormats {
    v.Date, parseErr = time.Parse(format, dateStr.String)
    if parseErr == nil {
        break // Successfully parsed
    }
}
if parseErr != nil {
    fmt.Fprintf(os.Stderr, "Error parsing date '%s' for version '%s': %v\n", dateStr.String, v.Name, parseErr)
}

This replaces the nested if-else with a loop for better maintainability and adds support for SQLite-specific formats.

cmd/generate_changelog/internal/changelog/generator.go

The change is in the early return condition in generateRawVersionContent():

// Before: Returned early if no commits
if len(prCommits) == 0 && len(directCommits) == 0 {
    return ""
}

// After: Also checks for PR numbers
if len(prCommits) == 0 && len(directCommits) == 0 && len(version.PRNumbers) == 0 {
    return ""
}

This ensures the function continues processing if there are PR numbers to include, preventing incomplete changelog entries.

Reason for Changes

  • Date Parsing Improvement: The original code failed to parse dates stored in SQLite's native DATETIME format, which includes timezone offsets and potential fractional seconds. This could cause errors when retrieving version data from the cache. By adding support for these formats, we ensure compatibility with various data sources and reduce parsing failures.
  • Version Content Fix: The generator was skipping versions with no commits but with associated PR numbers, leading to missing information in the changelog. This change ensures all relevant PR data is included, improving the completeness of generated changelogs.

Impact of Changes

  • Positive Impact: Increases reliability of changelog generation by handling more date formats and ensuring PR numbers are always considered. This could prevent incomplete or erroneous changelogs, especially in projects with mixed commit sources.
  • Performance: Minimal impact; the loop in date parsing adds negligible overhead since formats are tried sequentially and break on success. The generator change may slightly increase processing time for versions with PR numbers but no commits, as it avoids premature exits.
  • Compatibility: No breaking changes; the code remains backward compatible with existing RFC3339 formats.
  • Potential Bugs:
    • If a new date format emerges that's not covered, parsing could still fail—consider adding logging for unparsed dates to aid debugging.
    • The generator change assumes version.PRNumbers is populated correctly; if it's empty due to upstream issues, it might still return early unexpectedly.
    • No input validation on dateStr.String could lead to panics if it's nil or malformed, though the existing error handling mitigates this.

Test Plan

  • Unit Tests: Verify date parsing with various formats (e.g., SQLite DATETIME, RFC3339Nano) using mock data in cache_test.go. Ensure no regressions in existing RFC3339 parsing.
  • Integration Tests: Run the changelog generator on repositories with versions containing only PR numbers (no commits) and confirm they appear in output. Test with mixed commit/PR scenarios.
  • Edge Cases: Test with invalid dates to ensure error messages are logged without crashes. Validate behavior with empty PR lists.
  • Manual Testing: Generate changelogs for a sample repo and review for completeness.

Additional Notes

These changes were driven by real-world issues where SQLite-stored dates caused parsing errors and PR-only versions were omitted. The code is now more resilient, but monitoring for new date formats in production is recommended. No external dependencies were added.

## CHANGES

- Add SQLite datetime formats to version date parsing logic
- Loop through multiple date formats until one succeeds
- Include SQLite fractional seconds format support
- Prevent early return when version has PR numbers to output
- Simplify error handling for date parsing failures
@ksylvan ksylvan self-assigned this Jan 4, 2026
@ksylvan ksylvan merged commit c0d00ae into danielmiessler:main Jan 4, 2026
1 check passed
@ksylvan ksylvan deleted the kayvan/fix-generate-changelog-db-sync-issues branch January 4, 2026 19:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant