Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
30e9e71
ci: cover all consumer fixtures in style and strict typing gates
codeforester Oct 2, 2026
710208b
ci: keep Markdown examples under the documentation gate
codeforester Oct 2, 2026
8bb0562
fix: preserve consumer logging ownership and routing
codeforester Oct 2, 2026
6556889
perf: reuse logging locks and cache source paths
codeforester Oct 2, 2026
c87eeda
fix: enforce native Windows bundle retention safely
codeforester Oct 2, 2026
f0f9ece
ci: satisfy Windows retention style and typing checks
codeforester Oct 2, 2026
9679928
perf: skip contended retention housekeeping
codeforester Oct 2, 2026
6280ebb
security: bound and validate discovered project configuration
codeforester Oct 2, 2026
7db92d8
test: exercise recursion failures at bounded YAML composition
codeforester Oct 2, 2026
5e84077
fix: capture child and descriptor stdout in JSON envelopes
codeforester Oct 2, 2026
dd21781
ci: reconcile Project Intake through REST with scheduled recovery
codeforester Oct 2, 2026
a166e45
perf: cache second-precision human log timestamps
codeforester Oct 2, 2026
ee489ee
fix: preserve Python newline bytes in descriptor capture
codeforester Oct 2, 2026
baf0ff3
Merge branch 'enhancement/381-20261003-perf-lifecycle-logging-costs-1…
codeforester Oct 2, 2026
c7c21ae
Merge branch 'bug/378-20261003-bug-run-bundle-retention-is-inoperativ…
codeforester Oct 2, 2026
40b1401
Merge branch 'enhancement/386-20261003-perf-retention-serializes-conc…
codeforester Oct 2, 2026
74d2f5c
Merge branch 'security/385-20261003-security-validate-trust-of-ancest…
codeforester Oct 2, 2026
a83fa1f
Merge branch 'bug/379-20261003-bug-json-single-envelope-stdout-contra…
codeforester Oct 2, 2026
d352e43
Merge remote-tracking branch 'origin/main' into ci/393-20261003-ci-ru…
codeforester Oct 2, 2026
6ee5cc9
Merge branch 'ci/393-20261003-ci-ruff-check-and-mypy-do-not-cover-the…
codeforester Oct 2, 2026
f9787b1
Merge branch 'bug/387-20261003-bug-configure-logger-closes-consumer-o…
codeforester Oct 2, 2026
3780821
Merge branch 'enhancement/381-20261003-perf-lifecycle-logging-costs-1…
codeforester Oct 2, 2026
333ac40
Merge branch 'bug/378-20261003-bug-run-bundle-retention-is-inoperativ…
codeforester Oct 2, 2026
4f08c7d
Merge branch 'enhancement/386-20261003-perf-retention-serializes-conc…
codeforester Oct 2, 2026
369f986
Merge branch 'security/385-20261003-security-validate-trust-of-ancest…
codeforester Oct 2, 2026
514949a
Merge branch 'bug/379-20261003-bug-json-single-envelope-stdout-contra…
codeforester Oct 2, 2026
08017ed
ci: gate concurrent retention and logging throughput
codeforester Oct 2, 2026
fbe36d6
release: prepare 0.5.0 candidate and migration guidance
codeforester Oct 2, 2026
6e4394f
fix: avoid racing Windows lock-sidecar initialization
codeforester Oct 2, 2026
bd210cd
Merge branch 'enhancement/381-20261003-perf-lifecycle-logging-costs-1…
codeforester Oct 2, 2026
f1bda9a
Merge branch 'bug/378-20261003-bug-run-bundle-retention-is-inoperativ…
codeforester Oct 2, 2026
a1683c4
Merge branch 'enhancement/386-20261003-perf-retention-serializes-conc…
codeforester Oct 2, 2026
5f39a1f
Merge branch 'security/385-20261003-security-validate-trust-of-ancest…
codeforester Oct 2, 2026
7c65de4
Merge branch 'bug/379-20261003-bug-json-single-envelope-stdout-contra…
codeforester Oct 2, 2026
727d575
Merge branch 'ci/311-20261003-v1-0-make-project-intake-resilient-to-g…
codeforester Oct 2, 2026
da28ad5
Merge branch 'ci/391-20261003-ci-add-concurrency-and-log-throughput-s…
codeforester Oct 2, 2026
73770a5
ci: separate sustained persistence cost from hosted filesystem tails
codeforester Oct 2, 2026
bdf26d9
Merge branch 'ci/393-20261003-ci-ruff-check-and-mypy-do-not-cover-the…
codeforester Oct 2, 2026
c3eb5dc
Merge branch 'bug/387-20261003-bug-configure-logger-closes-consumer-o…
codeforester Oct 2, 2026
0597aaa
Merge branch 'enhancement/381-20261003-perf-lifecycle-logging-costs-1…
codeforester Oct 2, 2026
b24372d
Merge branch 'bug/378-20261003-bug-run-bundle-retention-is-inoperativ…
codeforester Oct 2, 2026
d1fd067
Merge branch 'enhancement/386-20261003-perf-retention-serializes-conc…
codeforester Oct 2, 2026
5ba2267
Merge branch 'security/385-20261003-security-validate-trust-of-ancest…
codeforester Oct 2, 2026
77618cb
Merge branch 'bug/379-20261003-bug-json-single-envelope-stdout-contra…
codeforester Oct 2, 2026
268bb7d
Merge branch 'ci/311-20261003-v1-0-make-project-intake-resilient-to-g…
codeforester Oct 2, 2026
8ca0027
docs: regenerate public API signatures for configuration trust options
codeforester Oct 2, 2026
9191a7e
Merge branch 'bug/387-20261003-bug-configure-logger-closes-consumer-o…
codeforester Oct 2, 2026
b7fd5df
Merge branch 'enhancement/381-20261003-perf-lifecycle-logging-costs-1…
codeforester Oct 2, 2026
331e583
Merge branch 'enhancement/386-20261003-perf-retention-serializes-conc…
codeforester Oct 2, 2026
6ba56eb
Merge branch 'security/385-20261003-security-validate-trust-of-ancest…
codeforester Oct 2, 2026
5d8860e
docs: regenerate public API signatures for configuration trust options
codeforester Oct 2, 2026
6e9d231
Merge branch 'bug/378-20261003-bug-run-bundle-retention-is-inoperativ…
codeforester Oct 2, 2026
e10d684
Merge branch 'ci/391-20261003-ci-add-concurrency-and-log-throughput-s…
codeforester Oct 2, 2026
dcb4dff
Merge branch 'ci/311-20261003-v1-0-make-project-intake-resilient-to-g…
codeforester Oct 2, 2026
682811f
Merge branch 'bug/379-20261003-bug-json-single-envelope-stdout-contra…
codeforester Oct 2, 2026
039564e
docs: use a published changelog URL in migration guidance
codeforester Oct 2, 2026
07d5301
ci: calibrate logging budget from hosted macOS measurements
codeforester Oct 2, 2026
f78c756
Merge branch 'ci/391-20261003-ci-add-concurrency-and-log-throughput-s…
codeforester Oct 2, 2026
857e52e
Merge main for branch maintenance (#426)
codeforester Oct 4, 2026
b48e444
Merge updated PR #414 for branch maintenance (#426)
codeforester Oct 4, 2026
0441cec
Merge updated PR #419 for branch maintenance (#426)
codeforester Oct 4, 2026
9012457
Merge updated PR #418 for branch maintenance (#426)
codeforester Oct 4, 2026
96fba37
Merge updated PR #422 for branch maintenance (#426)
codeforester Oct 4, 2026
f5330b2
Merge updated PR #420 for branch maintenance (#426)
codeforester Oct 4, 2026
65a3689
Merge updated PR #421 for branch maintenance (#426)
codeforester Oct 4, 2026
c4af745
Merge updated PR #417 for branch maintenance (#426)
codeforester Oct 4, 2026
66ce268
Merge updated PR #415 for branch maintenance (#426)
codeforester Oct 4, 2026
e82ce1f
Merge updated PR #416 for branch maintenance (#426)
codeforester Oct 4, 2026
2a0a9bb
fix: preserve incomplete JSON stdout captures
codeforester Oct 5, 2026
3d397ae
security: clarify discovered config verification
codeforester Oct 5, 2026
82f5df1
release: address changelog and migration review
codeforester Oct 5, 2026
b7f54fe
ci: isolate scheduled Project reconciliation failures
codeforester Oct 5, 2026
8826871
ci: control hosted contention benchmark batches
codeforester Oct 5, 2026
b00c288
fix: defer contended retention index refresh
codeforester Oct 5, 2026
9db3464
fix: preserve logger routing and levels
codeforester Oct 5, 2026
fbcc75c
fix: harden logging caches and sidecar locks
codeforester Oct 5, 2026
841d1e6
fix: handle Windows retention reparse leaves
codeforester Oct 5, 2026
72336ec
ci: expose consumer typing source coverage
codeforester Oct 5, 2026
3b4fc3f
docs: document process-wide JSON capture
codeforester Oct 5, 2026
311c280
test: verify retention converges after contention
codeforester Oct 5, 2026
ae935d1
fix: serialize logger reconfiguration
codeforester Oct 5, 2026
ff3f148
security: make trust errors actionable
codeforester Oct 5, 2026
97135b0
fix: type incomplete capture failures explicitly
codeforester Oct 5, 2026
f15f2c2
style: clean retention convergence test
codeforester Oct 5, 2026
990cb66
style: format typing gate test
codeforester Oct 5, 2026
59c7249
fix: validate README against latest published release
codeforester Oct 5, 2026
9ba2a3a
fix: preserve incomplete JSON stdout captures
codeforester Oct 5, 2026
eb3ae08
docs: document process-wide JSON capture
codeforester Oct 5, 2026
73b7eb7
fix: type incomplete capture failures explicitly
codeforester Oct 5, 2026
50b0695
style: format sidecar lock condition
codeforester Oct 5, 2026
c8e829d
Merge remote-tracking branch 'origin/enhancement/381-20261003-perf-li…
codeforester Oct 5, 2026
496decf
style: format retention lock logging
codeforester Oct 5, 2026
0f35aae
Merge remote-tracking branch 'origin/main' into ci/393-20261003-ci-ru…
codeforester Oct 5, 2026
6efcb60
test: cover debug logging with consumer handlers
codeforester Oct 5, 2026
436807b
test: cover concurrent and inherited logging state
codeforester Oct 5, 2026
2a916ea
test: verify Windows retention pinning and reparse cleanup
codeforester Oct 5, 2026
3f58457
Merge remote-tracking branch 'origin/ci/393-20261003-ci-ruff-check-an…
codeforester Oct 5, 2026
92cad10
Merge remote-tracking branch 'origin/bug/387-20261003-bug-configure-l…
codeforester Oct 5, 2026
e15763e
Merge remote-tracking branch 'origin/enhancement/381-20261003-perf-li…
codeforester Oct 5, 2026
2f96072
Merge remote-tracking branch 'origin/bug/378-20261003-bug-run-bundle-…
codeforester Oct 5, 2026
5e8e01f
Merge remote-tracking branch 'origin/enhancement/386-20261003-perf-re…
codeforester Oct 5, 2026
40d9e2a
Merge remote-tracking branch 'origin/security/385-20261003-security-v…
codeforester Oct 5, 2026
52f2e4e
Merge remote-tracking branch 'origin/bug/379-20261003-bug-json-single…
codeforester Oct 5, 2026
54be619
Merge remote-tracking branch 'origin/ci/311-20261003-v1-0-make-projec…
codeforester Oct 5, 2026
e059756
Merge remote-tracking branch 'origin/ci/391-20261003-ci-add-concurren…
codeforester Oct 5, 2026
89b3404
style: format changelog validation diagnostic
codeforester Oct 5, 2026
9c9b56f
docs: clarify host logging level behavior
codeforester Oct 5, 2026
7001a5d
fix: calibrate macOS logging benchmark budget
codeforester Oct 5, 2026
c1ff77a
Merge remote-tracking branch 'origin/ci/391-20261003-ci-add-concurren…
codeforester Oct 5, 2026
51b411d
fix: allow hosted macOS logging tails
codeforester Oct 5, 2026
8eb6d0c
Merge remote-tracking branch 'origin/ci/391-20261003-ci-add-concurren…
codeforester Oct 5, 2026
1cddd44
fix: calibrate Unix logging benchmark budget
codeforester Oct 5, 2026
7a620df
Merge remote-tracking branch 'origin/ci/391-20261003-ci-add-concurren…
codeforester Oct 5, 2026
df6ee90
fix: relax Unix logging benchmark edge
codeforester Oct 5, 2026
845e505
Merge remote-tracking branch 'origin/ci/391-20261003-ci-add-concurren…
codeforester Oct 5, 2026
4cd6b8d
Merge main into 0.5.0 release candidate
codeforester Oct 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and versions are tracked in the repo-root `VERSION` file.

- Continue compatibility hardening and adoption work for the next release.

## [0.5.0] - 2026-10-03

### Added

- Publish versioned, comparative CLI benchmark reports with lifecycle and
Expand Down Expand Up @@ -391,7 +393,8 @@ the API stability policy and migration guide before upgrading from `0.3.x`.
- Pinned the build backend to metadata compatible with the bundled publication
action and made license-file validation portable across setuptools versions.

[Unreleased]: https://github.com/basefoundry/base-cli/compare/v0.4.3...HEAD
[Unreleased]: https://github.com/basefoundry/base-cli/compare/v0.5.0...HEAD
[0.5.0]: https://github.com/basefoundry/base-cli/compare/v0.4.3...v0.5.0
[0.4.3]: https://github.com/basefoundry/base-cli/compare/v0.4.2...v0.4.3
[0.4.2]: https://github.com/basefoundry/base-cli/compare/v0.4.1...v0.4.2
[0.4.1]: https://github.com/basefoundry/base-cli/compare/v0.4.0...v0.4.1
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
| --- | --- | --- | --- |
| `0.4.3` | [Apache-2.0](LICENSE) | `python -m pip install base-cli` | [v0.4.3](https://github.com/basefoundry/base-cli/releases/tag/v0.4.3) |

Source release candidate: 0.5.0. Publication is pending the [release checklist](docs/release-0.5.0-checklist.md); PyPI remains the authority for available versions.

`base-cli` is the production lifecycle layer for Click and Typer Python CLIs.
It standardizes context, logging, configuration, cleanup, and machine-readable
contracts while leaving command and product policy in the consumer application.
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.3
0.5.0
33 changes: 33 additions & 0 deletions docs/migration-0.5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Migrating from 0.4.x to 0.5.0

0.5.0 is a pre-1.0 minor release. It retains the Click/Typer lifecycle APIs while
strengthening configuration, output, logging, retention, and release contracts.
The published 0.4.3 tag and distributions remain immutable.

- Convenience-profile project configuration now verifies POSIX ownership and
permissions, refuses symlink/reparse paths, and stops discovery at `.git`, a
filesystem boundary, or the configured ancestor limit. Repair permissions or
set `verify_discovered_config=False` explicitly for a knowingly shared
workspace; see [local configuration](local-config.md).
- YAML inputs are bounded before alias construction. Split unusually large
configuration files and remove recursive or excessive alias graphs.
- JSON mode captures descriptor and inherited child stdout. Wait for children
and flush native stdio before returning. Output over 8 MiB produces an error;
a detached child produces `capture_incomplete` with the partial captured
output; use NDJSON for larger streams. See [JSON contracts](json-contracts.md).
- Consumer logging handlers and configured levels survive CLI cleanup. Foreign
handlers and parent routing are preserved while `--debug` and `--quiet` still
control the Base-owned stream. An explicitly configured host logger level may
filter persistent DEBUG messages; a foreign handler without a level does not.
Configure the host logger at DEBUG when those records are required. See
[integrations](integrations.md).
- Native Windows enforces bundle retention through pinned directory handles;
contended maintenance passes skip without blocking command execution.
- Repeated source paths and human log timestamps are cached; log-sidecar I/O
errors use logging's error path without aborting commands.
- Click 8.5 is supported within the declared Click window. Typer consumers must
use the documented compatible Click/Typer pairs.

Review the dated [changelog](https://github.com/basefoundry/base-cli/blob/main/CHANGELOG.md) and the [platform boundary](platform-support.md)
when upgrading. Test the installed wheel in a clean environment, including your
JSON consumers, config permissions, and host logging integration.
26 changes: 26 additions & 0 deletions docs/release-0.5.0-checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# 0.5.0 release candidate checklist

This is release preparation. A dated changelog section does not mean the version
has been tagged or published. The proposed date must be refreshed if publication
happens on another day. Issue #307 remains open until publication evidence exists.

1. Merge the reviewed 0.5.0 issue train and all remaining 0.5.0 PRs. Refresh the
release PR against their final integrated commit and include their changelog
entries in 0.5.0 before approval.
2. Obtain independent approval and passing required checks on the exact release
head. Keep the repository and environment approval rules in place.
3. Validate the 0.4.x migration boundary in [migration guidance](migration-0.5.md),
then run the full local gate and hosted platform, dependency, consumer,
benchmark, package, and provenance checks.
4. Rehearse the reviewed artifact through the protected TestPyPI environment.
Install exactly `base-cli==0.5.0` from a new environment and run lifecycle/JSON
smoke checks; retain the artifact digest and workflow URL.
5. After the release PR is merged, create annotated `v0.5.0` on the independently
approved protected-main commit. Never alter `v0.4.3` or its distributions.
6. Approve the protected production environment. Publish the exact reviewed
wheel/sdist, then verify matching SHA256SUMS, SPDX SBOM, provenance and SBOM
attestations, RELEASE-BOM-ROW, tag target, and GitHub release assets.
7. Verify a clean installation of exactly `base-cli==0.5.0` from PyPI. Record the
immutable release URL and evidence on #307, then close it.

The operational commands and recovery rules remain in [Releasing](releasing.md).
8 changes: 8 additions & 0 deletions docs/releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,11 @@ rerun the workflow before creating a tag. If TestPyPI succeeds but a production
publish fails, inspect the workflow logs and rerun the same approved tag only
after confirming that neither artifact nor metadata needs correction. A version
that was published successfully must be incremented for the next release.

## 0.5.0 preparation

Use the [0.5.0 checklist](release-0.5.0-checklist.md) and
[0.4.x migration notes](migration-0.5.md). The changelog validator permits the
newest section matching `VERSION` to precede its tag while preparing a release
PR; all earlier published sections remain checked against their tags. Once the
current tag exists, its section is immutable too.
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ nav:
- Dependency support: dependency-support.md
- Optional output dependencies: optional-output-dependencies.md
- Migration guide: migrations.md
- Migrating to 0.5.0: migration-0.5.md
- Click migration: migration-click.md
- Typer migration: migration-typer.md
- Cement migration: migration-cement.md
Expand All @@ -66,3 +67,4 @@ nav:
- Runtime threat model: security-threat-model.md
- Security release review: security-review.md
- Releasing base-cli: releasing.md
- 0.5.0 release checklist: release-0.5.0-checklist.md
21 changes: 20 additions & 1 deletion scripts/validate_changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ def _validate_published_sections(
"""Ensure every released section remains identical to its version tag."""

errors: list[str] = []
version_file = path.parent / "VERSION"
candidate = version_file.read_text(encoding="utf-8").strip() if version_file.is_file() else None
for version in versions:
if version == "Unreleased":
continue
Expand All @@ -140,13 +142,30 @@ def _validate_published_sections(
capture_output=True,
text=True,
)
except (OSError, subprocess.CalledProcessError) as exc:
except subprocess.CalledProcessError as exc:
# A release PR necessarily precedes its protected-main tag. Only
# the newest section matching VERSION may be an untagged candidate;
# every earlier release remains bound to its immutable tag.
if version == candidate and len(versions) > 1 and version == versions[1]:
exists = subprocess.run(
Comment thread
codeforester marked this conversation as resolved.
["git", "-C", str(path.parent), "rev-parse", "--verify", f"refs/tags/{tag}"],
capture_output=True,
text=True,
check=False,
)
if exists.returncode == 1 or exists.returncode == 128:
continue
detail = getattr(exc, "stderr", None) or str(exc)
errors.append(
f"cannot verify [{version}] against tag {tag}: {detail.strip()}; "
"fetch the release tags before validating"
)
continue
except OSError as exc:
errors.append(
f"cannot verify [{version}] against tag {tag}: {exc}; fetch the release tags before validating"
)
continue
tagged_lines = completed.stdout.splitlines()
current_section = _section_text(lines, version)
tagged_section = _section_text(tagged_lines, version)
Expand Down
2 changes: 2 additions & 0 deletions scripts/validate_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@
"migration-click.md",
"migration-typer.md",
"migrations.md",
"migration-0.5.md",
"output-contracts.md",
"optional-output-dependencies.md",
"performance.md",
"testing.md",
"platform-support.md",
"releasing.md",
"release-0.5.0-checklist.md",
"security-review.md",
"security-threat-model.md",
"schemas.md",
Expand Down
24 changes: 24 additions & 0 deletions tests/test_validate_changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,19 @@ def test_rejects_edits_to_a_published_section(self) -> None:
errors = validate_changelog.validate_changelog(path, verify_tags=True)
self.assertIn("published changelog section [1.0.0] differs from tag v1.0.0", errors)

def test_current_untagged_release_candidate_can_be_prepared(self) -> None:
with tempfile.TemporaryDirectory() as tmpdir:
path = Path(tmpdir) / "CHANGELOG.md"
path.write_text(VALID_CHANGELOG, encoding="utf-8")
(path.parent / "VERSION").write_text("1.0.0\n")
missing = subprocess.CalledProcessError(128, "git", stderr="missing tag")
with mock.patch(
"scripts.validate_changelog.subprocess.run",
side_effect=[missing, subprocess.CompletedProcess("git", 128)],
):
errors = validate_changelog.validate_changelog(path, verify_tags=True)
self.assertEqual(errors, [])

def test_reports_unavailable_release_tags(self) -> None:
with tempfile.TemporaryDirectory() as directory:
path = Path(directory) / "CHANGELOG.md"
Expand All @@ -91,6 +104,17 @@ def test_reports_unavailable_release_tags(self) -> None:
errors = validate_changelog.validate_changelog(path, verify_tags=True)
self.assertTrue(any("fetch the release tags" in error for error in errors))

def test_reports_missing_git_without_retrying_with_an_uncaught_oserror(self) -> None:
with tempfile.TemporaryDirectory() as directory:
path = Path(directory) / "CHANGELOG.md"
path.write_text(VALID_CHANGELOG, encoding="utf-8")
with mock.patch(
"scripts.validate_changelog.subprocess.run",
side_effect=OSError("git is not installed"),
):
errors = validate_changelog.validate_changelog(path, verify_tags=True)
self.assertTrue(any("git is not installed" in error for error in errors))


if __name__ == "__main__":
unittest.main()
6 changes: 4 additions & 2 deletions tests/validate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ for file in "${required_files[@]}"; do
done

version="$(head -n 1 VERSION | tr -d '\r')"
published_version="$(git tag --list 'v[0-9]*' --sort=-version:refname | sed -n '1p' | sed 's/^v//')"
published_version="${published_version:-$version}"
readme_head="$(sed -n '1,18p' README.md | tr -d '\r')"
if ! printf '%s\n' "$readme_head" | grep -F "[![Tests](https://img.shields.io/github/actions/workflow/status/basefoundry/base-cli/tests.yml?branch=main&label=tests)](https://github.com/basefoundry/base-cli/actions/workflows/tests.yml)" >/dev/null; then
printf 'README.md is missing the main-branch tests health badge.\n' >&2
Expand All @@ -77,8 +79,8 @@ if ! printf '%s\n' "$readme_head" | grep -F "[![Python](https://img.shields.io/p
printf 'README.md is missing the supported Python versions badge.\n' >&2
exit 1
fi
if ! printf '%s\n' "$readme_head" | grep -F "| \`$version\` | [Apache-2.0](LICENSE) | \`python -m pip install base-cli\` | [v$version](https://github.com/basefoundry/base-cli/releases/tag/v$version) |" >/dev/null; then
printf 'README.md release strip does not match VERSION (%s), license, install command, and release link.\n' "$version" >&2
if ! printf '%s\n' "$readme_head" | grep -F "| \`$published_version\` | [Apache-2.0](LICENSE) | \`python -m pip install base-cli\` | [v$published_version](https://github.com/basefoundry/base-cli/releases/tag/v$published_version) |" >/dev/null; then
printf 'README.md release strip does not match the latest published tag (%s), license, install command, and release link.\n' "$published_version" >&2
exit 1
fi

Expand Down
Loading