Use this runbook for metadata updates, version bumps, validation, GitHub releases, and CocoaPods publication. Keep command outputs and upstream refs in the pull request so future releases can audit the release decision from code and logs instead of memory.
- Patch release: bug fixes or metadata-only updates.
- Minor release: additive public API, new modules, or metadata work that also changes public behavior beyond freshness.
- Major release: breaking API or packaging changes.
Metadata-only releases should normally be patch releases. Do not add local metadata overrides unless the requirements in docs/METADATA_PATCH_POLICY.md are met.
Start from a clean working tree:
git status --shortCheck the current local metadata ref and latest upstream candidate:
swift scripts/checkMetadataFreshness.swift --output .build/metadata-freshnessReview these generated artifacts before deciding scope:
.build/metadata-freshness/metadata-diff-summary.md.build/metadata-freshness/metadata-update-issue.md.build/metadata-freshness/metadata-update-pr.md.build/metadata-freshness/metadata-update-log-entry.md
If the release is for a user-reported numbering-plan issue, add or run a focused regression test that proves the old metadata fails and the new metadata fixes the case.
Run the all-in-one metadata updater first. Use --dry-run to validate downloads, parsing, and generated outputs without changing checked-in metadata:
swift scripts/updateMetadata.swift <metadata-ref> --dry-runUpdate all checked-in metadata families:
swift scripts/updateMetadata.swift <metadata-ref>Limit the update when only specific metadata families are in scope:
swift scripts/updateMetadata.swift <metadata-ref> --only main,geocoding
swift scripts/updateMetadata.swift <metadata-ref> --skip carrier,timezonesThe wrapper runs these underlying generators in order:
scripts/metadataGenerator.swiftfor main, testing, and short-number metadata.scripts/updateGeocodingMetadata.swiftfor geocoding databases.scripts/updateCarrierMetadata.swiftfor carrier metadata.scripts/updateTimeZonesMetadata.swiftfor timezone metadata.scripts/checkMetadataFreshness.swift --current-ref <metadata-ref>after checked-in updates.
Use the individual generator scripts only when debugging or intentionally updating one metadata family outside the normal release flow.
Update all project, podspec, dependency, and README version references:
swift scripts/updateProjectVersions.swift <new-version>Confirm version alignment:
swift scripts/checkVersionConsistency.swiftRun upstream parity checks against the exact metadata ref:
swift scripts/checkUpstreamTestParity.swift --upstream-ref <metadata-ref>
swift scripts/checkUpstreamAPIParity.swift --upstream-ref <metadata-ref>Run the local SwiftPM baseline:
swift test
LC_ALL=ko_KR.UTF-8 LANG=ko_KR.UTF-8 swift test
swift build -c release
git diff --checkRun the main Xcode schemes:
swift scripts/testXcodeSchemes.swiftIf the simulator destination is ambiguous, use a concrete UDID:
xcodebuild -scheme libPhoneNumber -showdestinations
swift scripts/testXcodeSchemes.swift --destination 'id=<simulator-udid>'Run CocoaPods lint for every shipped podspec when packaging, dependency, or release metadata changed:
swift scripts/publishPodspecs.swift --lintThe all-in-one updater runs the freshness check after checked-in updates. Run it manually only if you used --skip-freshness-check or individual generator scripts:
swift scripts/checkMetadataFreshness.swift --current-ref <metadata-ref> --output .build/metadata-freshnessUpdate docs/METADATA_UPDATE_LOG.md for metadata releases. Include:
- Previous local upstream ref.
- New upstream ref.
- Which metadata families changed.
- Issue-specific verification, when applicable.
- Commands that were run.
- Test, parity, build, lint, and freshness results.
The generated .build/metadata-freshness/metadata-update-log-entry.md is a starting point, not a substitute for recording release-specific results.
Open a pull request that includes:
- Upstream metadata ref or source commit.
- Summary of changed metadata families and behavior impact.
- Links to issue-specific verification, if any.
- Upstream parity results.
- Local validation results.
- CocoaPods lint results when podspecs or packaging are affected.
Do not publish CocoaPods podspecs until the release commit is merged and the GitHub release/tag exists.
After merge, create the GitHub release for the new version tag. The tag must match each podspec s.source tag and s.version.
Before publishing, confirm the version alignment from the release checkout:
swift scripts/checkVersionConsistency.swiftCheck the dependency-aware publish plan first:
swift scripts/publishPodspecs.swiftPublish missing podspec versions in dependency order:
swift scripts/publishPodspecs.swift --publishThe publish script:
- Discovers all root
*.podspecfiles. - Parses actual podspec dependencies with
pod ipc spec. - Orders local podspecs so prerequisites publish before dependents.
- Skips versions that already exist on trunk.
- Checks trunk visibility after every push.
- Treats timeout or server errors as inconclusive until
pod trunk infoconfirms whether the version exists.
If CocoaPods trunk returns a timeout or internal server error, do not change podspecs as a workaround. Re-run the script; it will skip versions that became visible and retry only missing versions.
After publication, run:
swift scripts/publishPodspecs.swiftThe release is complete only when every podspec version is reported as present on trunk.
Record any CocoaPods trunk incidents in the release notes or maintenance log when they affected the release process.