diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..c69dd8fa --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,827 @@ +# Changelog + +All notable changes to `libphonenumber-csharp` and its companion `libphonenumber-csharp.extensions` +package are documented here. + +**This project's release cadence is unusual for a changelog.** Nearly every release exists purely to +track a new upstream [google/libphonenumber](https://github.com/google/libphonenumber) metadata +release (about every two weeks), cut automatically by +[`create_new_release_on_new_metadata_update.yml`](.github/workflows/create_new_release_on_new_metadata_update.yml). +Those releases get a single mechanical entry here, added by +[`lib/github-actions-metadata-update.sh`](lib/github-actions-metadata-update.sh) in the very same +commit that syncs the metadata — nothing here is guessed ahead of time, since the version number is +already known: it's copied straight from the upstream tag being synced. + +That said, **real work constantly lands on `main` between metadata syncs and rides along in whatever +release happens to come next** — a version number by itself says nothing about how much changed. +This file was rebuilt from the actual commit history (not from the version-number pattern) to reflect +that: every release range that touched hand-written source, tests, docs, CI/build configuration, or a +shipped package's dependencies gets its own entry, sized to what actually happened — a one-liner for +a small fix, several bullets under `### Added`/`### Fixed`/`### Changed`/`### Performance` for a +large one. Two categories of file changes are folded into the plain metadata-sync entries even though +they're not `resources/*.xml` themselves, because they carry no hand-authored content: the generated +`LocaleData.cs` (regenerated by the same script from the local JDK on every sync, see +[`lib/DumpLocale.java`](lib/DumpLocale.java)) and version-bump-only touches to a `.csproj`/`.sln`/ +`appveyor.yml` (a bumped version string, nothing else in the diff). Long runs of releases with +*no* such changes are condensed into a single ranged entry so this file stays readable; every release +still has a matching entry, so no version number is skipped. One stretch of early history (October +2019) briefly synced this repo's full upstream multi-language source tree (`cpp/`, `java/`, +`debian/`) alongside the C# port; those files are called out but not itemized. + +**Folding is automatic going forward.** [`lib/update-changelog.sh`](lib/update-changelog.sh), called +from the same sync script, checks whether anything outside `resources/` changed on `main` since the +last release. If not, it either starts a new one-release entry or, when the release immediately above +it is *also* an automated metadata-only entry, extends that entry's range instead of adding another +one — so a long stretch of routine syncs keeps collapsing into a single entry the way the historical +ranges above do, without a human curating it. The moment a release includes anything else, it always +gets its own standalone entry and breaks the chain: it can't extend the run above it, and — because a +hand-written or substantive entry never carries the marker a foldable run needs — the next metadata-only +release starts a fresh run rather than reaching past it to resume the old one. + +Entries that describe an actual code change were written by hand at review time, tracing each claim +back to the commit(s) or PR(s) named next to it. For the exhaustive per-PR detail behind any release +(including the routine ones), see its +[GitHub Release](https://github.com/twcclegg/libphonenumber-csharp/releases), whose notes are +auto-generated from merged PR titles. + +Format loosely follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versioning tracks +whatever upstream `google/libphonenumber` release this port is synced to, not strict +[SemVer](https://semver.org/) — see +["Why keep libphonenumber-csharp up to date?"](README.md#why-keep-libphonenumber-csharp-up-to-date) +in the README for why staying current matters even for patch-looking bumps. + + + +## [v9.0.38](https://github.com/twcclegg/libphonenumber-csharp/compare/v9.0.37...v9.0.38) - 2026-08-28 + +A larger-than-usual release: the metadata-sync automation itself was reworked, alongside a batch of +Extensions API additions, security/hardening fixes, and a large internal code-quality pass. + +### Added +- (Extensions) `PhoneNumber.TryParse`/`TryParseValid` 2-argument overloads matching the conventional + .NET `TryParse` shape; `PhoneNumberTypeConverter` for `TypeConverter`-based binding (config + binding, `PropertyGrid`, etc.); `PhoneNumberAttribute`, a `DataAnnotations` `ValidationAttribute` + backed by real validation (`PhoneNumberUtil.IsValidNumber`) instead of the framework's loose + `[Phone]` regex. (#405) +- A SharpFuzz/FsCheck-based fuzzing target for the parsing surface (`PhoneNumbers.Fuzz`, not part of + the solution, run weekly by `fuzz.yml`). (#392) +- Build-provenance attestation for the published NuGet packages. (#400) + +### Changed +- Metadata-sync automation now opens a PR (authenticated as a dedicated `libphonenumber-csharp-bot` + account, not the ambient `GITHUB_TOKEN`) and auto-merges it, instead of pushing straight to `main`. + (#431, #434) `finalize_metadata_release.yml` then tags the merge commit and dispatches the NuGet + publish. This CHANGELOG's own entries are now written into that same commit by the sync script. +- Migrated the solution file to the `.slnx` format. (#388) +- Upgraded bUnit to 2.x, clearing a transitive `AngleSharp` advisory (GHSA-pgww-w46g-26qg). (#398) +- Moved the locale country-names table out of generated C# and into a binary resource per country, + read on demand by `LocaleNames` (mirrors the phone/short-number/geocoding "binary metadata" move + from v9.0.29–v9.0.32, below); `LocaleData` still exposes the whole table for callers outside the + library. (#395) +- Dropped the restore lock files and locked-mode CI restores added the previous release (v9.0.37) — + they didn't earn their complexity; `NuGetAudit` and pinned-exact-versions-in-`Directory.Packages.props` + do the job restore locking was meant for. (#396) Package-validation baselines for both packable + projects now compare against the 9.0.37 release. (#394) +- A large batch of purely internal idiomatic-C# cleanups (`is`-null pattern matching, `TryGetValue`, + LINQ `Select`/`Where`, `??=`, sealing singleton-style types, `BinaryPrimitives` in `ByteBuffer`) and + CodeQL-driven fixes (redundant `ToString()`/`GetHashCode()` calls, `GetType()` comparisons, + invariant-culture formatting) — no behavior change. (#409, #412–#421, #424 and others) +- CodeQL now runs on manual dispatch as well as its schedule, and excludes generated `obj/` output. + (#407, #423) + +### Fixed +- Security: a path-traversal issue in `BuildLocaleNames` and an uncaught parse exception in + `PhoneNumberTypeConverter`. (#428) +- `NumberParseException` (rather than `ArgumentOutOfRangeException`) on malformed RFC3966 + `phone-context` ordering. (#406) +- Several `PhoneNumberMatcher`/`AsYouTypeFormatter` parity gaps against the upstream Java source, + including `formattingRuleHasFirstGroupOnly` and `containsMoreThanOneSlashInNationalNumber`. (#408) +- Unbounded growth in `AsYouTypeFormatter` and missing null-guards in `PhoneNumberUtil`. (#402) +- `FormatOutOfCountryKeepingAlphaChars` no longer throws when region metadata is missing. + +### Docs +- Reconciled stale `Todo` sections and refreshed documentation for the binary-metadata, build, and CI + changes made across v9.0.29–v9.0.38. + +## [v9.0.37](https://github.com/twcclegg/libphonenumber-csharp/compare/v9.0.36...v9.0.37) - 2026-08-14 + +A dedicated performance-optimization release, alongside build-reproducibility and package-validation +work and new benchmark coverage. + +### Performance +- A long series of allocation- and regex-reduction changes on the parsing/formatting hot path: + matching against slices instead of materializing them, skipping regex match groups when stripping a + national prefix, capturing every extension alternative into one named group, truncating the lookup + prefix by integer division instead of a string round-trip, reading the flyweight prefix-map buffer + from an array instead of a stream, and not rendering the country-calling-code test to a string. +- Froze the country-calling-code-to-region-code map and the short-number/timezone lookup tables into + frozen collections; sized the `Normalize` stack buffer to the input instead of a fixed allocation. + +### Added +- Benchmarks for the offline geocoder (previously untested for performance); new benchmarks + measuring the parse, validate, and format phases separately and covering cold-start and + representative real-world input shapes; a robustness benchmark/test checking the public API + survives hostile input. +- CI now benchmarks the base commit on the same runner as the PR branch before posting a comparison, + and only reports statistically significant changes (finished the following release, v9.0.38's + `#425`). + +### Changed +- Enabled `EnablePackageValidation` on both packable projects (`PhoneNumbers`, `PhoneNumbers.Extensions`). +- Restore lock files were committed and checked in CI for reproducible restores (reverted again the + next release, v9.0.38, above, once it was clear the complexity wasn't paying for itself). +- Centralized build settings into `Directory.Build.props` and package versions into + `Directory.Packages.props` (Central Package Management) — the structure CLAUDE.md now documents. +- Pinned the SDK major version and added a build-reproducibility check; cached NuGet packages in CI. +- Dropped the out-of-support `net9.0` target framework and the `netframework4.8` test target; guarded + nullable annotations by TFM name rather than by .NET version. +- `NuGetAudit` findings no longer fail the build outright. + +### Fixed +- The offline geocoder threw instead of returning nothing for a region with no localized name. +- A race between parallel inner builds cleaning the generated binary-metadata output. +- `GetSupportedRegions` returned a mutable reference instead of a copy; region sets are now frozen. +- Oversized input could overflow the stack buffer in `Normalize`. +- The release tag is now pinned to the commit just pushed, fixing a release-tag-determinism bug. +- Exceptions thrown from `PhoneNumberUtil` now format with invariant culture and name their arguments. + +## [v9.0.36](https://github.com/twcclegg/libphonenumber-csharp/compare/v9.0.35...v9.0.36) - 2026-08-03 + +### Changed +- Removed AppVeyor entirely — CI is GitHub Actions only from here on (matches CLAUDE.md's "There are + no Windows runners"). +- Compatible workflows now run on ARM64 runners for faster builds. +- `lib/github-actions-metadata-update.sh` gained a `--dry-run` option, opt-in overrides for the + java/proto-file check, hardening for bash 3.2, scoped git identity, and no longer hard-codes the + target repository. +- The GitHub Release now links back to the published NuGet packages and the upstream libphonenumber + release it tracks; `publish_nuget.yml` is dispatched only after the release tag is created; CI now + verifies release packaging directly. +- Ported the corresponding upstream Java behavior changes for v9.0.36. + +## [v9.0.35](https://github.com/twcclegg/libphonenumber-csharp/compare/v9.0.34...v9.0.35) - 2026-07-17 + +Metadata release; the metadata-update script's temporary java-file-check override from the previous +release was restored to its normal (enforcing) state. + +## [v9.0.34](https://github.com/twcclegg/libphonenumber-csharp/compare/v9.0.33...v9.0.34) - 2026-07-03 + +Minor CI/tooling release: rotated the NuGet API key, moved AppVeyor to VS2026 with .NET 10, and +temporarily relaxed the metadata script's java-file check to let this sync through (restored the +next release, above). + +## [v9.0.33](https://github.com/twcclegg/libphonenumber-csharp/compare/v9.0.32...v9.0.33) - 2026-06-22 + +Security- and process-hardening release, alongside two metadata-parity fixes. + +### Added +- `SECURITY.md`, `CODE_OF_CONDUCT.md`, and `CODEOWNERS`. +- [OpenSSF Scorecard](https://securityscorecards.dev/) workflow (`scorecard.yml`), running on `main` + and on branch-protection changes. +- Deterministic-build verification. + +### Fixed +- Hardened the custom-metadata XML parser (`BuildMetadataFromXml`, used by the legacy + `PhoneNumberUtil(Stream)` constructor) against XXE (XML External Entity) attacks. +- Hardened GitHub Actions workflows following security best practices (least-privilege permissions, + pinned actions) and refreshed several READMEs to match. +- Ported an upstream v9.0.33 E.164 short-code fix and a previously-missed Mexican (MX) area-code + change from v9.0.30 (above). + +## [v9.0.32](https://github.com/twcclegg/libphonenumber-csharp/compare/v9.0.31...v9.0.32) - 2026-06-05 + +This release shipped a new target framework, AOT compatibility, and a redesigned demo site. + +### Added +- `net10.0` target framework. (#328) +- Cold-start benchmarks, in addition to the existing steady-state ones. + +### Changed +- Made the library AOT-compatible (`IsAotCompatible`, trim/AOT analyzer warnings now build errors on + modern TFMs) — the Blazor WASM demo depends on this too. +- Beautified the Blazor demo website's UI. (#348) +- Reduced the performance-test job's scope for CI speed; restored `System.IO.Compression` after an + earlier removal attempt (v9.0.31, below) needed it back. + +## [v9.0.31](https://github.com/twcclegg/libphonenumber-csharp/compare/v9.0.30...v9.0.31) - 2026-05-23 + +### Added +- A Blazor WebAssembly demo site (`PhoneNumbers.Demo`), deployed to GitHub Pages by + `deploy-demo.yml` — doubles as proof the library works trimmed under WASM. (#342, #343) +- Cross-platform embedded debug symbols for both packages. (#340) +- Test coverage for `DataModelsAndExceptions` and `BuildPrefixMapFromBin`. (#337) +- CodeQL now also runs on pull requests, not just on a schedule. (#332) + +### Changed +- Refactored the offline geocoder to use the binary prefix map the same way the Java version does. + (#334) +- Removed the now-unneeded `System.IO.Compression` package reference. (#339) +- Several fixes to how the performance-test PR comment reports its results. (#335, #336, #338) +- Dependabot now also tracks the new demo projects' dependencies. (#344) + +## [v9.0.30](https://github.com/twcclegg/libphonenumber-csharp/compare/v9.0.29...v9.0.30) - 2026-05-07 + +The architectural turning point behind most of CLAUDE.md's "Singleton + metadata loading" notes: phone +metadata moved from parsed XML to binary files generated at build time and embedded in the assembly. +(`net10.0` landed the release after this one — v9.0.32, above.) + +### Added +- `IMetadataLoader` + a lazy `MetadataSource`, with `EmbeddedResourceMetadataLoader` as the default + implementation reading per-region binary files generated at build time by the new + `PhoneNumbers.MetadataBuilder` project. +- `PhoneNumberToCarrierMapper`, matching a feature already present in the Java library. (#317) +- Much larger performance-test datasets (100,000 entries instead of the previous size). (#319) + +### Changed +- **Metadata pipeline rewrite**: `BuildMetadataFromXml` and the geocoding/timezone text metadata are + now converted to per-region binary files at build time (`BuildBinaryMetadata`, `BuildGeocodingBins`, + `BuildTimezoneBin` MSBuild targets) and read from embedded, gzip-compressed resources at runtime — + XML is no longer parsed on the default load path. `PhoneNumberUtil`/`MetadataManager` switched to + the new lazy `MetadataSource`; the old `RegexCache`-based approach was removed where superseded. + Made the multi-TFM build of the binary metadata race-free. +- Dropped `intlFormat` instead of emitting a literal `"NA"` when the upstream XML value is `NA`. (#97) + +### Performance +- Enabled compiled regex for dynamic metadata patterns; cached `GetOrAdd` factory delegates in the + metadata and regex caches; shared the national-significant-number string between region lookup and + validation instead of recomputing it; skipped a redundant `StringBuilder` copy in + `MaybeExtractCountryCode`. + +### Fixed +- Ported several additional upstream Java behavior fixes as part of the metadata-pipeline work. + +## [v9.0.10 – v9.0.29](https://github.com/twcclegg/libphonenumber-csharp/compare/v9.0.9...v9.0.29) - 2025-07-18 – 2026-04-25 + +20 releases. Upstream metadata syncs, several bundled only a mechanical `LocaleData.cs` regeneration, +plus routine Dependabot CI bumps (`codecov-action`, `actions/checkout`, `actions/setup-dotnet`, +`github/codeql-action`) and NuGet test-project dependency groups. No changes to the library's own +source. + +## [v9.0.9](https://github.com/twcclegg/libphonenumber-csharp/compare/v9.0.8...v9.0.9) - 2025-07-08 + +- Fixed a test failure caused by a `System.Collections.Immutable` behavior change by upgrading the + package. (#297) + +## [v9.0.2 – v9.0.8](https://github.com/twcclegg/libphonenumber-csharp/compare/v9.0.1...v9.0.8) - 2025-03-28 – 2025-06-25 + +7 releases, metadata syncs plus a `codecov-action` version bump and mechanical `LocaleData.cs` +regenerations. No source changes. + +## [v9.0.1](https://github.com/twcclegg/libphonenumber-csharp/compare/v9.0.0...v9.0.1) - 2025-03-23 + +- Reverted the assembly strong-name signing added one release earlier in v9.0.0 (below), after it + caused problems for consumers. (#291) + +## [v9.0.0](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.55...v9.0.0) - 2025-03-11 + +- **Breaking:** both packages' assemblies are strong-name signed. (#288) Bumped the major version + because it changes assembly identity — reverted the very next release, v9.0.1 above, after it + turned out to break more consumers than it helped. + +## [v8.13.51 – v8.13.55](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.50...v8.13.55) - 2024-12-02 – 2025-02-14 + +5 releases, mostly metadata syncs and routine Dependabot/`codecov-action` bumps. CodeQL's build step +picked up .NET 8. (#274) One doc fix: the bug-report issue template was updated to ask reporters for +more detail. (#278) + +## [v8.13.50](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.49...v8.13.50) - 2024-11-16 + +- Added: `net9.0` target framework (dropped again once out of support — see v9.0.36–v9.0.37 above). + (#273) + +## [v8.13.49](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.48...v8.13.49) - 2024-11-04 + +Metadata-only release. No source changes. + +## [v8.13.48](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.47...v8.13.48) - 2024-10-23 + +- Updated the JSON library dependency used by the `libphonenumber-csharp.extensions` package. + +## [v8.13.45 – v8.13.47](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.44...v8.13.47) - 2024-09-06 – 2024-10-04 + +3 releases, metadata syncs plus routine Dependabot test-dependency bumps (`Microsoft.NET.Test.Sdk`) +and one mechanical `LocaleData.cs` regeneration. No source changes. + +## [v8.13.44](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.43...v8.13.44) - 2024-08-26 + +- Added: `net8.0` target framework; dropped `net7.0`. (#264) + +## [v8.13.42 – v8.13.43](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.41...v8.13.43) - 2024-07-26 – 2024-08-09 + +2 releases, metadata syncs plus routine Dependabot test-dependency bumps. No source changes. + +## [v8.13.41](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.40...v8.13.41) - 2024-07-25 + +- Bumped `System.Text.Json` in `libphonenumber-csharp.extensions`. (#258) + +## [v8.13.40](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.39...v8.13.40) - 2024-07-03 + +- Fixed: area-code information was lost for all Mexican (MX) numbers. + +## [v8.13.38 – v8.13.39](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.37...v8.13.39) - 2024-06-05 – 2024-06-15 + +2 releases, metadata syncs plus routine Dependabot/`codecov-action` bumps. No source changes. + +## [v8.13.37](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.36...v8.13.37) - 2024-05-17 + +- Code coverage now runs and uploads on every PR, not only on `main`; removed the now-redundant + standalone coverage workflow. (#250) + +## [v8.13.36](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.35...v8.13.36) - 2024-05-03 + +- Added the GitHub Action that uploads code-coverage results. (#245) Fixed coverage not being + generated for the `PhoneNumbers.Test` project. (#246) Moved the PR template since it wasn't being + applied by default. (#247) + +## [v8.13.35](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.34...v8.13.35) - 2024-04-19 + +Metadata release; only a mechanical `LocaleData.cs` regeneration alongside it. + +## [v8.13.34](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.33...v8.13.34) - 2024-04-05 + +A foundational release for this repo's current tooling — this is where nullable reference types, +the performance-test harness, and CodeQL scanning all began. + +### Added +- `PhoneNumbers.PerformanceTest`, the BenchmarkDotNet harness CLAUDE.md still describes today. (#240) +- CodeQL security scanning (`codeql.yml`). (#241) + +### Changed +- Enabled nullable reference types across the main `PhoneNumbers` project (later extended, per + CLAUDE.md, to every target except `netstandard2.0`). +- Updated the test projects to target .NET 8. +- Expanded documentation with concrete usage examples. (#238) + +## [v8.13.32 – v8.13.33](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.31...v8.13.33) - 2024-03-12 – 2024-03-25 + +2 releases, metadata sync plus a routine Dependabot test-dependency bump. No source changes. + +## [v8.13.31](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.30...v8.13.31) - 2024-02-25 + +- Fixed: `NormalizeDiallableCharsOnly` incorrectly removed the `#` symbol. (#230) +- Enabled nullable reference types for the `PhoneNumbers.Test` project; added more test coverage + derived from the main Google libphonenumber repository. (#224) + +## [v8.13.30](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.29...v8.13.30) - 2024-02-09 + +- Added GitHub Actions PR builds that build the project and run tests on Linux and Windows. (#204) + +## [v8.13.29](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.28...v8.13.29) - 2024-01-26 + +Metadata-only release. No source changes. + +## [v8.13.28](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.27...v8.13.28) - 2024-01-25 + +- Added an `.editorconfig` derived from Microsoft's defaults. (#222) +- Added more test coverage (`NumberFormat`, `ToString`, and other previously-uncovered methods). + (#219) + +## [v8.13.27](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.26...v8.13.27) - 2023-12-21 + +- Fixed: a null-reference exception during number normalization when given a null input. (#207) +- Updated number-splitting logic to match an upstream fix + ([google/libphonenumber#3305](https://github.com/google/libphonenumber/pull/3305)). + +## [v8.13.26](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.25...v8.13.26) - 2023-11-29 + +- Changed: metadata updates are now proposed and synced automatically by a new GitHub Actions script, + instead of by hand — the first `feat: automatic upgrade to vX.Y.Z` release, and the origin of most + of the release entries in this file from here on. (#192) + +## [v8.13.25](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.24...v8.13.25) - 2023-11-20 + +- Fixed: a leading `+` was incorrectly stripped/ignored when parsing. (#184) +- Added Dependabot configuration for NuGet package updates. (#185) +- A `net8.0` target-framework attempt was added and reverted the same release (real `net8.0` support + landed later, in v8.13.44 above, #264). + +## [v8.13.24](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.23...v8.13.24) - 2023-10-31 + +- Moved release/update scripts into a new `lib/` directory — the layout CLAUDE.md still documents, + and the home the metadata-automation script (v8.13.26, above) landed in shortly after. + +## [v8.13.22 – v8.13.23](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.21...v8.13.23) - 2023-09-29 – 2023-10-17 + +2 releases, metadata sync plus a CI tweak. No source changes. + +## [v8.13.20 – v8.13.21](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.19...v8.13.21) - 2023-09-07 – 2023-09-20 + +2 metadata-only releases. No source changes. + +## [v8.13.19](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.18...v8.13.19) - 2023-08-22 + +Metadata release with a minor accompanying test update. + +## [v8.13.18](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.17...v8.13.18) - 2023-08-03 + +- Changed: reduced allocations on the parsing/formatting hot path by skipping internal + protobuf-style builder objects. (#180) + +## [v8.13.17](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.16...v8.13.17) - 2023-07-26 + +- Changed: reduced unnecessary regex construction and usage on hot paths. (#178) Cleaned up package + dependencies. (#176) + +## [v8.13.16](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.15...v8.13.16) - 2023-07-11 + +Metadata-only release. No source changes. + +## [v8.13.15](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.14...v8.13.15) - 2023-07-11 + +Metadata release; a test method was extracted for reuse and the NuGet API key was rotated. + +## [v8.13.13 – v8.13.14](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.12...v8.13.14) - 2023-06-15 + +2 metadata-only releases (same day). No source changes. + +## [v8.13.12](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.11...v8.13.12) - 2023-06-15 + +Metadata release; documented the metadata-update process in more detail and refreshed the packed +README. + +## [v8.13.11](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.10...v8.13.11) - 2023-04-27 + +Metadata-only release. No source changes. + +## [v8.13.10](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.9...v8.13.10) - 2023-04-20 + +- Added: `net6.0` target framework. +- Changed: `Format()` uses stack-allocated `Span` instead of heap allocations on the + formatting hot path; several other methods optimized. (#166) + +## [v8.13.9](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.8...v8.13.9) - 2023-04-10 + +Metadata-only release. No source changes. + +## [v8.13.8](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.7...v8.13.8) - 2023-03-27 + +- Added (Extensions): a `System.Text.Json` converter for `PhoneNumber`. +- Changed: reworked how geocoding data is packaged — zipped for `net46`+ targets, embedded raw where + no zip exists, and built with `Microsoft.Bcl.Compression` for portable-library builds; removed the + old `net35`/`net40`/portable framework zips. (#147) + +## [v8.13.3 – v8.13.7](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.2...v8.13.7) - 2022-12-22 – 2023-03-03 + +5 releases, mostly metadata syncs plus release-script, CI, and test-tooling housekeeping (a +`System.Collections.Immutable` bump included). No functional library changes. + +## [v8.13.2](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.1...v8.13.2) - 2022-12-08 + +- Added: the `libphonenumber-csharp.extensions` NuGet package, for C#-idiomatic helpers with no + Java-upstream equivalent. (#164) +- Added: `PhoneNumberToTimeZonesMapper`, mapping a phone number to its candidate IANA time zones, + full-conformance ported from Google's Java implementation. (#163) +- Added: `net7.0` target framework. +- Changed: `RegexCache` is no longer LRU-evicted. + +## [v8.13.1](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.13.0...v8.13.1) - 2022-11-28 + +### Performance +- `RegexCache` lookups sped up by roughly 10x. (#161) + +### Changed +- Added Visual Studio 2022 support to CI. +- Removed the unused protobuf code-generation tooling (see v8.13.0, below). +- The NuGet package icon is now referenced via `PackageIcon` from the packed package instead of a URL. + +## [v8.13.0](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.57...v8.13.0) - 2022-11-08 + +- The old protobuf-based metadata code-generation path was dropped as no longer compatible with the + toolchain — metadata has been generated from XML only since (see csharp/README.md's "Known Issues" + for the XML-vs-protobuf divergence this leaves). + +## [v8.12.55 – v8.12.57](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.54...v8.12.57) - 2022-09-09 – 2022-10-14 + +3 releases, metadata syncs plus a release-script fix. No source changes. + +## [v8.12.54](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.53...v8.12.54) - 2022-08-22 + +Metadata release; removed an unused locale-data-dump helper class and cleaned up its supporting +tooling. + +## [v8.12.53](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.52...v8.12.53) - 2022-08-08 + +Metadata release; updated the `LocaleData` generator and its output rendering. + +## [v8.12.51.1 – v8.12.52](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.51...v8.12.52) - 2022-07-12 – 2022-07-19 + +2 metadata-only releases. No source changes. + +## [v8.12.51](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.50...v8.12.51) - 2022-07-07 + +Metadata release; rotated the NuGet API key and fixed file-name casing in a handful of test/source +files alongside a large upstream metadata sync. + +## [v8.12.48 – v8.12.50](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.47...v8.12.50) - 2022-05-18 – 2022-06-13 + +3 metadata-only releases. No source changes. + +## [v8.12.47](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.46...v8.12.47) - 2022-05-18 + +- Added GitHub issue templates. (#152) + +## [v8.12.44 – v8.12.46](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.43...v8.12.46) - 2022-02-24 – 2022-04-01 + +3 metadata-only releases. No source changes. + +## [v8.12.40 – v8.12.43](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.39...v8.12.43) - 2022-02-14 + +4 metadata-only patch releases shipped in quick succession right after v8.12.39, below. No source +changes. + +## [v8.12.39](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.38...v8.12.39) - 2022-02-14 + +- Removed: the `net35` target framework and other end-of-life targets. (#146) +- Added: a way to refresh a `PhoneNumberUtil` instance's metadata from a stream at runtime, without + restarting the process. (#142) +- The default branch was renamed to `main`. + +## [v8.12.35 – v8.12.38](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.34...v8.12.38) - 2021-12-15 + +4 metadata-only releases (same day) plus one test-only PascalCase rename fix. No functional changes. + +## [v8.12.30 – v8.12.34](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.29...v8.12.34) - 2021-08-18 – 2021-10-07 + +5 metadata-only releases. No source changes. + +## [v8.12.29](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.28...v8.12.29) - 2021-08-18 + +- Fixed a build-breaking syntax error in `AsYouTypeFormatter` introduced by the previous release. + +## [v8.12.28](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.27...v8.12.28) - 2021-07-22 + +Metadata-only release. No source changes. + +## [v8.12.27](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.26...v8.12.27) - 2021-07-08 + +- Enforced the maximum national-significant-number length during parsing. + +## [v8.12.26](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.25...v8.12.26) - 2021-06-25 + +Metadata-only release. No source changes. + +## [v8.12.25](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.24...v8.12.25) - 2021-06-16 + +- Fixed: always use the preferred international prefix when present, instead of falling back to the + default. +- Test projects moved to target `net5.0`. + +## [v8.12.22 – v8.12.24](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.21...v8.12.24) - 2021-04-30 – 2021-05-31 + +3 metadata-only releases (v8.12.24 bundled a one-line test-project touch alongside the metadata +sync). No functional changes. + +## [v8.12.16 – v8.12.21](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.15...v8.12.21) - 2021-01-15 – 2021-04-08 + +5 metadata-only releases. No source changes. + +## [v8.12.15](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.14...v8.12.15) - 2020-12-18 + +- Reverted the `System.Collections.Immutable` version bump from the previous release after it caused + problems. + +## [v8.12.14](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.13...v8.12.14) - 2020-12-04 + +- Updated the `System.Collections.Immutable` dependency. (#125) (Reverted the next release, above.) + +## [v8.12.11 – v8.12.13](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.10...v8.12.13) - 2020-10-09 – 2020-11-17 + +2 metadata-only releases. No source changes. + +## [v8.12.10](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.9...v8.12.10) - 2020-09-29 + +### Performance +- Optimized library startup time. (#121) + +## [v8.12.9](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.8...v8.12.9) - 2020-09-02 + +Metadata-only release. No source changes. + +## [v8.12.8](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.7...v8.12.8) - 2020-08-17 + +Metadata release; reverted a NuGet package-icon change back to referencing it via URL. + +## [v8.12.7](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.6...v8.12.7) - 2020-07-21 + +- Rotated the NuGet API key and cleaned up packaging/`xunit` build warnings. + +## [v8.12.5 – v8.12.6](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.4...v8.12.6) - 2020-06-04 – 2020-07-06 + +2 metadata-only releases. No source changes. + +## [v8.12.4](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.3...v8.12.4) - 2020-05-21 + +- Added a missing semicolon to `singleExtensionSymbolParsing`. (#117) + +## [v8.12.2 – v8.12.3](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.12.1...v8.12.3) - 2020-04-23 – 2020-05-08 + +2 metadata-only releases. No source changes. + +## [v8.12.0 – v8.12.1](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.11.5...v8.12.1) - 2020-03-20 – 2020-03-31 + +2 releases, each bundling only a one-line incidental touch (a generated region-code constant, a +version bump) alongside the metadata sync. No functional changes. + +## [v8.11.4 – v8.11.5](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.11.3...v8.11.5) - 2020-02-13 – 2020-03-03 + +2 metadata-only releases. No source changes. + +## [v8.11.3](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.11.2...v8.11.3) - 2020-02-03 + +- Fixed: numbers with multiple leading zeroes were parsed incorrectly. (#111) + +## [v8.11.0 – v8.11.2](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.23...v8.11.2) - 2019-11-29 – 2020-01-15 + +3 metadata-only releases. No source changes. + +## [v8.10.23](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.22...v8.10.23) - 2019-11-18 + +Metadata release; README updates. + +## [v8.10.22](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.21...v8.10.22) - 2019-10-31 + +Metadata release; updated dependent libraries. + +## [v8.10.21](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.20...v8.10.21) - 2019-10-16 + +- Removed the vendored copies of the upstream Java/C++/Debian-packaging source trees that had been + synced into the repository the previous release (below) — this port only carries the C# code from + here on. + +## [v8.10.20](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.19...v8.10.20) - 2019-10-03 + +- The full upstream multi-language source tree (`cpp/`, `java/`, `debian/` packaging) was synced into + the repository alongside the metadata — removed again the very next release, above. +- Fixed two French short-number classifications (`STANDARD_RATE`, toll-free) to match + `resources/ShortNumberMetadata.xml`. (#108) + +## [v8.10.19](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.18...v8.10.19) - 2019-09-21 + +Metadata-only release. No source changes. + +## [v8.10.18](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.17...v8.10.18) - 2019-09-16 + +Metadata release with a small accompanying `PhoneNumberUtil`/README touch-up. + +## [v8.10.17](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.16...v8.10.17) - 2019-08-16 + +Metadata release with a small accompanying `AsYouTypeFormatter`/`PhoneNumberUtil` fix. + +## [v8.10.15 – v8.10.16](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.14...v8.10.16) - 2019-07-18 – 2019-08-05 + +2 metadata-only releases. No source changes. + +## [v8.10.14](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.13...v8.10.14) - 2019-07-01 + +- Internal code-quality pass: added thread-safety locks and `IDisposable` where needed, switched + several collections to immutable equivalents, fixed a SonarQube (S1848) finding, and added more XML + doc comments. + +## [v8.10.13](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.12...v8.10.13) - 2019-05-31 + +Metadata-only release. No source changes. + +## [v8.10.12](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.11...v8.10.12) - 2019-05-15 + +- Converted JavaDoc-style comments to C# XML doc comments for `PhoneNumberUtil`, `AreaCodeMap`, + `AreaCodeMapStorageStrategy`, `AreaCodeParser`, `AsYouTypeFormatter`, and `IMatcherApi`, and enabled + `GenerateDocumentationFile` so they surface in IntelliSense. (#102, #103) + +## [v8.10.11](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.10...v8.10.11) - 2019-05-07 + +Metadata-only release. No source changes. + +## [v8.10.10](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.9...v8.10.10) - 2019-04-17 + +Metadata release with a ReSharper (`.DotSettings`) configuration touch-up. + +## [v8.10.9](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.8...v8.10.9) - 2019-04-05 + +Metadata-only release. No source changes. + +## [v8.10.8](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.7...v8.10.8) - 2019-03-23 + +Metadata release with a small accompanying `LeniencyExtensions`/`PhoneNumberMatcher`/`PhoneNumberUtil` +fix. + +## [v8.10.5 – v8.10.7](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.4...v8.10.7) - 2019-02-08 – 2019-03-11 + +3 metadata-only releases. No source changes. + +## [v8.10.4](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.3...v8.10.4) - 2019-01-24 + +Metadata-only release. No source changes. + +## [v8.10.3](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.2...v8.10.3) - 2019-01-11 + +- Cleaned up documentation for `GetLengthOfNationalDestinationCode` and removed unneeded + `AsYouTypeFormatter` code; dropped a bad transitive dependency from the Java demo project (unrelated + to the C# port). + +## [v8.10.2](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.1...v8.10.2) - 2018-12-06 + +- Added the NuGet package icon. + +## [v8.10.1](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.10.0...v8.10.1) - 2018-11-28 + +Metadata-only release. No source changes. + +## [v8.10.0](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.9.16...v8.10.0) - 2018-11-28 + +- Fixed `carrierCodeFormattingRule` handling and updated `AsYouTypeFormatter` behavior. (#89) +- Fixed a `net35` performance issue: check whether a dictionary key already exists before adding, to + avoid a thrown-and-caught `ArgumentException`. (#88) +- Reworked how the per-region embedded XML resources (added in v8.9.16, below) are deduplicated and + read. (#82) + +## [v8.9.16](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.9.15...v8.9.16) - 2018-10-19 + +- Use embedded XML resources for `.NET 3.5` instead of the standard resource pipeline. (#80) + +## [v8.9.15](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.9.14...v8.9.15) - 2018-10-06 + +- Added a code example to the README. (#76) +- Changed: `Leniency.Verify` moved to an extension method (`LeniencyExtensions`) to avoid a breaking + API change. (#75) + +## [v8.9.14](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.9.13...v8.9.14) - 2018-09-20 + +Metadata-only release. No source changes. + +## [v8.9.13](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.9.12...v8.9.13) - 2018-09-07 + +- Cleaned up Russian-character handling in `PhoneNumberUtil`. + +## [v8.9.11 – v8.9.12](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.9.10...v8.9.12) - 2018-08-18 – 2018-08-24 + +2 releases; v8.9.12 bundled a small incidental `PhoneNumberUtil` tweak with the metadata sync (no PR +or commit message recorded to describe it further). No new features. + +## [v8.9.9 – v8.9.10](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.9.8...v8.9.10) - 2018-06-29 – 2018-07-12 + +2 releases, metadata syncs. No source changes. + +## [v8.9.8](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.9.7...v8.9.8) - 2018-06-15 + +- Added: `ShortNumberUtil`, providing information about short codes — the predecessor of today's + `ShortNumberInfo`. (#64) +- Added tests and fixes for `MetadataFilter`. (#65) +- Excluded autogenerated files from the code-coverage report. (#66) + +## [v8.9.7](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.9.6.3...v8.9.7) - 2018-05-30 + +- CI/packaging tweaks (AppVeyor, PowerShell build scripts, portable-library packaging); added + `InternalRegexOptions`. + +## [v8.9.4.1 – v8.9.6.3](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.9.3...v8.9.6.3) - 2018-04-17 – 2018-05-16 + +3 metadata-only releases. No source changes. + +## [v8.9.3](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.9.2...v8.9.3) - 2018-04-05 + +- Added: a `net35` target framework, using embedded XML resources instead of the standard resource + pipeline. (#58) (Dropped again in v8.12.39, 2022-02-14, above.) + +## [v8.8.10 – v8.9.2](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.8.9...v8.9.2) - 2018-01-25 – 2018-03-19 + +5 releases, mostly metadata syncs. Added `CONTRIBUTING.md`; de-duplicated the test metadata XML. No +functional changes. + +## [v8.8.7 – v8.8.9](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.8.6...v8.8.9) - 2017-12-01 – 2018-01-10 + +4 metadata-only releases. No source changes. + +## [v8.8.6](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.8.5...v8.8.6) - 2017-11-17 + +- Changed: broad cleanup and simplification across the metadata/formatting classes (extreme + bracket-reduction logic removed, various simplifications). (#47) + +## [v8.8.5](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.8.4...v8.8.5) - 2017-10-31 + +Metadata-only release. No source changes. + +## [v8.8.4](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.8.3...v8.8.4) - 2017-10-17 + +- Fixed: handling of numbers with a leading zero. (#44) + +## [v8.8.2 – v8.8.3](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.8.1...v8.8.3) - 2017-09-22 – 2017-10-05 + +2 releases, packaging/version housekeeping only. No functional changes. + +## [v8.8.1](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.8.0...v8.8.1) - 2017-09-08 + +- Added: `netstandard2.0` target framework. +- Set up NuGet CI packaging. + +## [v8.8.0](https://github.com/twcclegg/libphonenumber-csharp/compare/v8.7.1...v8.8.0) - 2017-09-08 + +- Improved parsing logic to be smarter about national-prefix detection and stripping. +- `preferred_domestic_carrier_code` is no longer set when empty; an empty value passed in by a caller + is now treated as unset. +- General `AsYouTypeFormatter` updates and porting catch-up with the upstream Java source. + +## [v8.7.1](https://github.com/twcclegg/libphonenumber-csharp/releases/tag/v8.7.1) - 2017-08-03 + +Earliest release with a recoverable history and the baseline for this changelog. See +[GitHub Releases](https://github.com/twcclegg/libphonenumber-csharp/releases) for anything published +before it. diff --git a/README.md b/README.md index 4ad1d9a4..41c35d26 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ See [this](csharp/README.md) for details about the port. Phone number metadata is updated in the Google repo approximately every two weeks. This library is automatically updated by a [scheduled github action](https://github.com/twcclegg/libphonenumber-csharp/actions/workflows/create_new_release_on_new_metadata_update.yml) to include the latest metadata, usually within a day. See [Metadata updates](#metadata-updates) for how that works and how to run it manually. +See [CHANGELOG.md](CHANGELOG.md) for release history. + ## Installation Run the following command to add this library to your project @@ -185,7 +187,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for the build settings that will fail CI ## Metadata updates -The [`create_new_release_on_new_metadata_update`](https://github.com/twcclegg/libphonenumber-csharp/actions/workflows/create_new_release_on_new_metadata_update.yml) workflow runs daily and drives [`lib/github-actions-metadata-update.sh`](lib/github-actions-metadata-update.sh). When the latest `google/libphonenumber` release is newer than the published NuGet package, it copies the upstream `resources/`, regenerates `resources/locale/country_names.txt`, then commits, pushes to a `metadata-update/*` branch and opens a PR against `main` with auto-merge enabled. The push and PR authenticate as the dedicated `libphonenumber-csharp-bot` account (via the `BOT_ACCESS_TOKEN` secret) rather than the default `GITHUB_TOKEN`, since GitHub requires a maintainer to manually approve workflow runs on PRs opened with `GITHUB_TOKEN`. Once that PR's required checks pass and it merges, [`finalize_metadata_release`](https://github.com/twcclegg/libphonenumber-csharp/actions/workflows/finalize_metadata_release.yml) tags the merge commit, creates a matching GitHub release, and dispatches the NuGet publish. +The [`create_new_release_on_new_metadata_update`](https://github.com/twcclegg/libphonenumber-csharp/actions/workflows/create_new_release_on_new_metadata_update.yml) workflow runs daily and drives [`lib/github-actions-metadata-update.sh`](lib/github-actions-metadata-update.sh). When the latest `google/libphonenumber` release is newer than the published NuGet package, it copies the upstream `resources/`, regenerates `resources/locale/country_names.txt`, adds a [CHANGELOG.md](CHANGELOG.md) entry for the release, then commits, pushes to a `metadata-update/*` branch and opens a PR against `main` with auto-merge enabled. The push and PR authenticate as the dedicated `libphonenumber-csharp-bot` account (via the `BOT_ACCESS_TOKEN` secret) rather than the default `GITHUB_TOKEN`, since GitHub requires a maintainer to manually approve workflow runs on PRs opened with `GITHUB_TOKEN`. Once that PR's required checks pass and it merges, [`finalize_metadata_release`](https://github.com/twcclegg/libphonenumber-csharp/actions/workflows/finalize_metadata_release.yml) tags the merge commit, creates a matching GitHub release, and dispatches the NuGet publish. The changelog entry is written in the same PR rather than afterwards: `main`'s branch-protection ruleset requires every push to go through a PR with no bypass for any actor (including this automation's own bot account), so `finalize_metadata_release` — which only tags an existing commit and calls the Releases API — has no way to push a follow-up commit of its own. The version number is already known at PR-open time (it's copied straight from the upstream tag), so there's nothing to guess. Before doing any of that it inspects the upstream diff and stops if it contains `.java` or `.proto` files, because changes to the Java sources may need porting by hand and an unattended metadata bump would silently skip them. diff --git a/lib/github-actions-metadata-update.sh b/lib/github-actions-metadata-update.sh index f8d60467..138efbb4 100644 --- a/lib/github-actions-metadata-update.sh +++ b/lib/github-actions-metadata-update.sh @@ -329,6 +329,7 @@ if isTrue "${DRY_RUN}"; then log "dry run complete, a real run would now:" log " - replace ${GITHUB_ACTION_WORKING_DIRECTORY}/resources with $(find "${UPSTREAM_RESOURCES}" -type f | wc -l | tr -d ' ') files from ${UPSTREAM_GITHUB_RELEASE_TAG}" log " - regenerate resources/locale/country_names.txt with $(java -version 2>&1 | head -n 1 || echo 'the local jdk')" + log " - add a CHANGELOG.md entry for ${UPSTREAM_GITHUB_RELEASE_TAG}" log " - commit \"feat: automatic upgrade to ${UPSTREAM_GITHUB_RELEASE_TAG}\" on ${BRANCH} and push it" log " - open a PR from ${BRANCH} into main and enable auto-merge" log " - once that PR's required checks pass and it merges, finalize-metadata-release.sh creates release ${UPSTREAM_GITHUB_RELEASE_TAG} and dispatches ${PUBLISH_WORKFLOW}" @@ -361,6 +362,48 @@ if [ -z "$(git status --porcelain)" ]; then exit 0 fi +# Record this release in CHANGELOG.md in the same commit as the metadata sync, rather than as a +# separate PR once the tag exists: the version number is already known here (it's +# UPSTREAM_GITHUB_RELEASE_TAG itself - this port tracks upstream's version 1:1), so there is +# nothing to guess. The finalize step (finalize-metadata-release.sh) only tags and releases an +# existing commit; it can't push a follow-up commit of its own; main's branch-protection ruleset +# requires a PR for every push, with no bypass for any actor, including this automation's own +# bot account - the same reason this script opens a PR instead of pushing directly (see the +# file-level comment above). Doing it here keeps everything in the one PR that already goes +# through that ruleset. +CHANGELOG_FILE="${GITHUB_ACTION_WORKING_DIRECTORY}/CHANGELOG.md" +if [ -f "${CHANGELOG_FILE}" ] && grep -qF '' "${CHANGELOG_FILE}"; then + # Every release always includes a metadata sync (that's the only thing that ever cuts a tag), + # but some releases also bundle other work merged to `main` in between - a version number alone + # doesn't say which. Diff this repo's own history since the last release (not the upstream diff + # checked above, which is google/libphonenumber's) against everything but resources/ itself and + # this bookkeeping file, so update-changelog.sh can tell whether this release is foldable into a + # prior metadata-only run or needs its own standalone entry. Deliberately NOT excluded: + # CountryCodeToRegionCodeMap.cs - despite its name, it is hand-maintained (its own header still + # says "todo make this file automatically generated"), so a change to it is real, hand-relevant + # content, not a mechanical byproduct of this sync. Fetching just the one tag works even from a + # shallow checkout: a tree-level `git diff` needs both commits' trees, not a connected history + # between them. + METADATA_ONLY=true + if git fetch --quiet --depth=1 origin "refs/tags/v${DEPLOYED_NUGET_TAG}:refs/tags/v${DEPLOYED_NUGET_TAG}" 2>/dev/null \ + && git rev-parse -q --verify "v${DEPLOYED_NUGET_TAG}" >/dev/null; then + NON_METADATA_FILES=$(git diff --name-only "v${DEPLOYED_NUGET_TAG}" HEAD -- . ':!resources' ':!CHANGELOG.md') + if [ -n "${NON_METADATA_FILES}" ]; then + METADATA_ONLY=false + fi + else + # Fail closed: better to give this release its own entry than to silently fold real changes + # away as if they never happened because the one tag needed to check couldn't be fetched. + warn "could not fetch v${DEPLOYED_NUGET_TAG} to check for non-metadata changes since the last release" + METADATA_ONLY=false + fi + + bash "${SCRIPT_DIR}/update-changelog.sh" "${CHANGELOG_FILE}" "${GITHUB_REPOSITORY}" "${UPSTREAM_REPOSITORY}" \ + "v${DEPLOYED_NUGET_TAG}" "${UPSTREAM_GITHUB_RELEASE_TAG}" "${METADATA_ONLY}" "$(date -u +%F)" +else + warn "CHANGELOG.md missing or missing the '' marker, skipping changelog update" +fi + git checkout -b "${BRANCH}" git add -A git -c user.email='<>' -c user.name='libphonenumber-csharp-bot' \ @@ -372,7 +415,7 @@ git -c user.email='<>' -c user.name='libphonenumber-csharp-bot' \ git push --force origin "HEAD:refs/heads/${BRANCH}" PR_BODY=$(cat <&2 + # Also emit a GitHub Actions warning annotation, so a non-fatal problem shows up as a yellow + # banner on the workflow run summary instead of only a line buried in step output that nobody + # reads unless something else already prompted them to look - see the missing-CHANGELOG-marker + # warning in github-actions-metadata-update.sh for what this matters for. `%`, CR and LF have to + # be percent-escaped in the message: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions + local message="$*" + message="${message//%/%25}" + message="${message//$'\r'/%0D}" + message="${message//$'\n'/%0A}" + echo "::warning::${message}" } # fail diff --git a/lib/update-changelog.sh b/lib/update-changelog.sh new file mode 100755 index 00000000..6396883a --- /dev/null +++ b/lib/update-changelog.sh @@ -0,0 +1,167 @@ +#! /bin/bash +# Records one release in CHANGELOG.md, called from github-actions-metadata-update.sh in the same +# commit as the metadata sync. Every release always includes a metadata sync (that is the only +# thing that ever cuts a new tag - see finalize-metadata-release.sh); some releases also bundle +# other work that merged to `main` in the meantime. CHANGELOG.md was rebuilt once, by hand, to +# describe that other work accurately per release; this script only has to keep going from there +# without a human re-curating each entry. +# +# A run of consecutive metadata-only releases (no changes outside resources/) automatically folds +# into a single range entry, so the file does not grow one near-duplicate heading per fortnight +# forever - exactly like the "N releases" ranges already in the file from the historical rebuild, +# just generated instead of researched. A release that is NOT metadata-only always gets its own +# standalone entry and never gets folded into a neighboring run, in either direction: it cannot +# extend a prior run (its own content isn't metadata-only) and, because it carries no run marker +# of its own, a later metadata-only release cannot fold into it either - the next metadata-only +# release starts a brand new run instead. +# +# The fold state lives in an HTML comment immediately above the heading it describes: +# +# `from` is the tag right before the run started (the baseline for the compare link); `first` is +# the first tag actually in the run; `count` is how many consecutive metadata-only releases have +# folded into it so far. Only a heading with this marker directly above it is a candidate to +# extend - a human-written or pre-rebuild heading never has one, so it can never be mistaken for +# a foldable run. +# +# Usage: update-changelog.sh +# [date:YYYY-MM-DD] +set -euo pipefail + +usage() { + cat >&2 <<'EOF' +Usage: update-changelog.sh [date:YYYY-MM-DD] +EOF +} + +if [ "$#" -lt 6 ]; then + echo "missing required argument" >&2 + usage + exit 2 +fi + +CHANGELOG_FILE="$1" +GITHUB_REPO="$2" +UPSTREAM_REPO="$3" +FROM_TAG="$4" +NEW_TAG="$5" +METADATA_ONLY="$6" +DATE="${7:-$(date -u +%F)}" + +if [ "${METADATA_ONLY}" != "true" ] && [ "${METADATA_ONLY}" != "false" ]; then + echo "metadata-only must be \"true\" or \"false\", got: ${METADATA_ONLY}" >&2 + usage + exit 2 +fi + +NEXT_ENTRY_MARKER='' +RUN_MARKER_RE='^$' + +mapfile -t LINES <"${CHANGELOG_FILE}" + +MARKER_INDEX=-1 +for i in "${!LINES[@]}"; do + if [ "${LINES[${i}]}" = "${NEXT_ENTRY_MARKER}" ]; then + MARKER_INDEX=${i} + break + fi +done +if [ "${MARKER_INDEX}" -lt 0 ]; then + echo "could not find \"${NEXT_ENTRY_MARKER}\" in ${CHANGELOG_FILE}" >&2 + usage + exit 2 +fi + +# The line right after the marker (skipping one blank line, which is how every existing entry in +# the file is spaced from the one above it) is the only place a foldable run marker can be. +CANDIDATE_INDEX=$((MARKER_INDEX + 1)) +if [ "${CANDIDATE_INDEX}" -lt "${#LINES[@]}" ] && [ "${LINES[${CANDIDATE_INDEX}]}" = "" ]; then + CANDIDATE_INDEX=$((CANDIDATE_INDEX + 1)) +fi + +RUN_MATCHED=false +if [ "${METADATA_ONLY}" = "true" ] && [[ "${LINES[${CANDIDATE_INDEX}]:-}" =~ ${RUN_MARKER_RE} ]]; then + RUN_MATCHED=true + RUN_FROM="${BASH_REMATCH[1]}" + RUN_FIRST="${BASH_REMATCH[2]}" + RUN_START_DATE="${BASH_REMATCH[3]}" + RUN_COUNT="${BASH_REMATCH[4]}" +fi + +formatDateRange() { + if [ "$1" = "$2" ]; then printf '%s' "$1"; else printf '%s – %s' "$1" "$2"; fi +} + +compareLink() { printf 'https://github.com/%s/compare/%s...%s' "$1" "$2" "$3"; } +upstreamReleaseLink() { printf 'https://github.com/%s/releases/tag/%s' "$1" "$2"; } + +# buildMetadataOnlyBlock +buildMetadataOnlyBlock() { + local from=$1 first=$2 startDate=$3 count=$4 latest=$5 date=$6 + local heading dateRange link markerLine body + if [ "${count}" -eq 1 ]; then heading="${first}"; else heading="${first} – ${latest}"; fi + dateRange=$(formatDateRange "${startDate}" "${date}") + link=$(compareLink "${GITHUB_REPO}" "${from}" "${latest}") + markerLine="" + if [ "${count}" -eq 1 ]; then + body="Metadata update to upstream [libphonenumber ${latest}]($(upstreamReleaseLink "${UPSTREAM_REPO}" "${latest}"))." + else + body="${count} consecutive metadata-only releases (no changes to hand-written source, tests, docs, or CI/build configuration). Latest upstream sync: [libphonenumber ${latest}]($(upstreamReleaseLink "${UPSTREAM_REPO}" "${latest}"))." + fi + printf '%s\n## [%s](%s) - %s\n\n%s\n' "${markerLine}" "${heading}" "${link}" "${dateRange}" "${body}" +} + +# buildSubstantiveBlock +buildSubstantiveBlock() { + local from=$1 tag=$2 date=$3 + local link body + link=$(compareLink "${GITHUB_REPO}" "${from}" "${tag}") + body="Includes the metadata sync to upstream [libphonenumber ${tag}]($(upstreamReleaseLink "${UPSTREAM_REPO}" "${tag}")) plus other changes merged to \`main\` since the last release — see the compare link above for the full diff." + printf '## [%s](%s) - %s\n\n%s\n' "${tag}" "${link}" "${date}" "${body}" +} + +if ${RUN_MATCHED}; then + NEW_BLOCK=$(buildMetadataOnlyBlock "${RUN_FROM}" "${RUN_FIRST}" "${RUN_START_DATE}" "$((RUN_COUNT + 1))" "${NEW_TAG}" "${DATE}") + REPLACE_FROM=${CANDIDATE_INDEX} + # The block being replaced is: marker, heading, blank, then one or more body lines running up + # to (but not including) the next blank line or the end of the file. Measuring it here, rather + # than assuming a fixed length, means this still splices out exactly the right span if + # buildMetadataOnlyBlock's body ever grows past one line. + END=$((CANDIDATE_INDEX + 3)) + while [ "${END}" -lt "${#LINES[@]}" ] && [ "${LINES[${END}]}" != "" ]; do + END=$((END + 1)) + done + REPLACE_COUNT=$((END - CANDIDATE_INDEX)) +else + if [ "${METADATA_ONLY}" = "true" ]; then + NEW_BLOCK=$(buildMetadataOnlyBlock "${FROM_TAG}" "${NEW_TAG}" "${DATE}" 1 "${NEW_TAG}" "${DATE}") + else + NEW_BLOCK=$(buildSubstantiveBlock "${FROM_TAG}" "${NEW_TAG}" "${DATE}") + fi + # Insert as a new block right after the marker, pushing whatever was there down. + REPLACE_FROM=$((MARKER_INDEX + 1)) + REPLACE_COUNT=0 +fi + +TMP_FILE=$(mktemp) +trap 'rm -f "${TMP_FILE}"' EXIT + +{ + for ((i = 0; i < REPLACE_FROM; i++)); do + printf '%s\n' "${LINES[${i}]}" + done + # Only the insert path needs a blank line ahead of the new block: the lines already emitted + # above stop right at the marker text itself there, with no separating blank line yet. The + # fold path's REPLACE_FROM already points at the existing run marker, so the blank line above + # it (the one separating it from whatever precedes it) was already emitted in the loop above - + # adding another one here would double it up. + if [ "${REPLACE_COUNT}" -eq 0 ]; then + printf '\n' + fi + printf '%s\n' "${NEW_BLOCK}" + for ((i = REPLACE_FROM + REPLACE_COUNT; i < ${#LINES[@]}; i++)); do + printf '%s\n' "${LINES[${i}]}" + done +} >"${TMP_FILE}" + +mv "${TMP_FILE}" "${CHANGELOG_FILE}" +trap - EXIT