Skip to content

Patch fixes for v3.0.2#7

Merged
jlevy merged 6 commits into
masterfrom
claude/determined-pascal-X4VbB
May 23, 2026
Merged

Patch fixes for v3.0.2#7
jlevy merged 6 commits into
masterfrom
claude/determined-pascal-X4VbB

Conversation

@jlevy

@jlevy jlevy commented May 23, 2026

Copy link
Copy Markdown
Owner

Summary

Originally scoped as patch fixes for v3.0.2; grew during the session to also include tbd setup, a copier template upgrade to v0.2.25, and a publishing workflow modernization. Four commits, each logically distinct — happy to split before merge if you'd rather land them separately.

Commits

  1. 54e255b Fixes for v3.0.2 patch release — the original patch work. See bug-fix list below.
  2. 58eea68 Add tbd v0.1.28 project setup — adds .tbd/ and .claude/ from tbd setup --auto --prefix=strif. Orthogonal to the patch fixes.
  3. 606e08a Upgrade simple-modern-uv template from v0.2.7 to v0.2.25copier update --vcs-ref=v0.2.25. Bumps GH Actions, uv, and dev deps. Reorgs docs into docs/.
  4. beaae43 Make publish.yml tag-triggered with auto GitHub Release — mirrors the jlevy/tbd pattern so any agent can release end-to-end with just git tag vX.Y.Z && git push --tags.

Bug fixes (commit 1, the patch fixes)

  • Build is broken on current uv-dynamic-versioning: bump = "true" (string) is rejected — must be boolean. Fresh uv sync and editable installs were failing.
  • FD leak in temp_output_file: mkstemp() returns (fd, path) but cleanup only removed the file. Confirmed with /proc/self/fd accounting — 5 successive with blocks leaked 5 FDs. Fix closes the fd in cleanup, wrapped in try/except OSError so user-closed FDs don't blow up.
  • Broken script entry point: strif = "strif:main" referenced a nonexistent function. Removed; a real CLI is deferred to a later minor release.
  • is_truthy had a dead bool branch: isinstance(True, int) is True, so the bool check was never reached. Reordered so the bool branch is checked first.
  • move_file was checking the wrong path for the backup-decision condition (src_path.exists() instead of dest_path.exists()).
  • copy_to_backup raised on missing source, while its sibling move_to_backup silently returned. Now consistent.
  • Missing Python 3.10 classifier despite requires-python = ">=3.10".
  • _RANDOM.seed() is a no-op on random.SystemRandom. Removed.
  • DEV_NULL was defined but not exported — added to __all__.

Tests (commit 1)

New tests/test_files.py with 18 tests covering each fixed function plus the previously-untested headline atomic_output_file. Uses pytest's tmp_path fixture. Total suite is 26 tests, all green.

Template upgrade (commit 3)

copier update --vcs-ref=v0.2.25. Project-specific content preserved by three-way merge.

  • GitHub Actions: checkout@v4 → @v6, setup-uv@v5 → @v7, uv 0.6.14 → 0.10.2
  • Dev deps: pytest 8 → 9, ruff 0.11 → 0.15, rich 13 → 14, basedpyright 1.28 → 1.38, +pytest-sugar
  • uv sync --all-extras --devuv sync --all-extras (dev deps in [dependency-groups] are auto-included)
  • CI matrix: kept Python 3.10, added 3.14 → now ["3.10", "3.11", "3.12", "3.13", "3.14"]
  • Docs reorganized into docs/ subdirectory
  • LICENSE copyright year bumped

Publishing workflow (commit 4)

Adopts the jlevy/tbd pattern:

  • Trigger on push: tags: ['v*'] (was release: published)
  • Auto-creates GitHub Release via softprops/action-gh-release@v2 with generated notes
  • Auto-marks - tags as prereleases
  • workflow_dispatch retained for manual fallback

Once merged, releasing v3.0.2 is git tag v3.0.2 && git push --tags.

Test plan

  • uv run pytest — 26/26 pass
  • uv run python devtools/lint.py — clean
  • uv sync succeeds (was failing before the bump = true fix)
  • CI green on 3.10–3.13 (3.14 not in matrix until after merge)
  • After merge: tag v3.0.2 to trigger the modernized publish workflow

https://claude.ai/code/session_01Td1N9waEtmcArZh5jNBdLH

claude added 5 commits May 23, 2026 00:26
- Fix uv-dynamic-versioning: bump must be a boolean, not string
  (was breaking `uv sync` and editable installs on current versions).
- Remove broken `strif:main` script entry point (no such function).
- Add Python 3.10 to classifiers (was missing despite `requires-python >=3.10`).
- Fix file descriptor leak in `temp_output_file`: cleanup now closes the
  fd returned by `mkstemp`, not just removes the file.
- Reorder `is_truthy` so the bool branch runs (was dead code since bool
  is a subclass of int). Behavior was correct by coincidence; now correct
  by construction.
- Fix `move_file` to check `dest_path.exists()` for the backup decision
  (was checking `src_path.exists()` — confusing read, accidentally
  worked).
- `copy_to_backup` is now silent on missing source, matching
  `move_to_backup`. Previously raised `FileNotFoundError`.
- Remove `_RANDOM.seed()` — no-op on `random.SystemRandom`.
- Add `DEV_NULL` to `__all__` so it's available as a convenience handle
  via `from strif import DEV_NULL`.

Tests: add `tests/test_files.py` with coverage for `atomic_output_file`
(happy path, exception leaves partial, backup, make_parents, target-is-dir
raises, force replaces dir), `temp_output_file` (no fd leak,
double-close tolerated), `temp_output_dir`, `is_truthy` (bool, string,
numeric, sized, strict), `copy_to_backup`, and `move_file`. 26 tests
total now pass.
Initialize tbd issue tracker with prefix `strif` (rendered as `strif-N`).
Adds .tbd/ config and .claude/ integration files. Sync branch: tbd-sync.

Note: this commit is orthogonal to the v3.0.2 patch fixes also on this
branch — feel free to split out before merging if you prefer to land
them separately.
Done via `copier update --vcs-ref=v0.2.25`. Project-specific content
(README body, src/, tests/) preserved by three-way merge.

Workflow modernization:
- actions/checkout v4 -> v6, astral-sh/setup-uv v5 -> v7
- uv 0.6.14 -> 0.10.2
- `uv sync --all-extras --dev` -> `uv sync --all-extras` (dev deps are
  now in [dependency-groups], `--all-extras` already covers them)
- Publish step: switched from `pypa/gh-action-pypi-publish@release/v1`
  to `uv publish --trusted-publishing always` (PyPA action is now the
  documented alternative in a comment, for easy reversion)

CI matrix conflict resolved manually: kept Python 3.10 support and
added 3.14 — strif still requires-python = ">=3.10,<4.0", so 3.10-3.14
is the matrix.

Dev dependency upgrades:
- pytest 8.3.5 -> 9.0.2
- ruff 0.11.0 -> 0.15.1
- rich 13.9.4 -> 14.3.2
- basedpyright 1.28.2 -> 1.38.0
- funlog 0.2.0 -> 0.2.1
- new: pytest-sugar 1.1.1 (prettier pytest output)
- pyproject: add Python 3.14 classifier; fix commented ruff rule
  trailing-comma syntax

Other:
- Docs moved from project root to docs/ subdir (installation.md,
  development.md, publishing.md). README links updated.
- LICENSE: copyright year 2025 -> 2026
- devtools/lint.py: KeyboardInterrupt handler, `--stats` on basedpyright
- Makefile: drop `--dev` from `uv sync`, `make upgrade` now upgrades
  all deps including dev

26 tests still pass, lint clean.
Adopt the pattern used in jlevy/tbd so any agent (or human) can cut a
release end-to-end with just `git tag vX.Y.Z && git push --tags`.
Removes the manual "create a GitHub Release" step that previously
required a UI click or an extra `gh release create` call.

Changes:
- Trigger on `push: tags: ['v*']` instead of `release: published`.
- Add `contents: write` permission so the workflow can create releases.
- Add softprops/action-gh-release@v2 step to auto-create the GitHub
  Release with generate_release_notes (uses PR titles since last tag).
- Auto-set prerelease=true when the tag contains `-` (e.g., `-rc.1`).
- Keep `workflow_dispatch` for manual fallback.

Docs (docs/publishing.md) updated to describe the new flow: push tag,
optionally edit notes after via `gh release edit`. First-time-setup
section also updated to use the new tag-push trigger.
Found during pre-release supply-chain audit. pygments is a transitive
dep (pulled via rich for terminal syntax highlighting in lint output)
and the CVE was present in master too — not introduced by this PR.

rich 15.0.0 already allows pygments<3.0.0,>=2.13.0, so the bump is
compatible. pip-audit reports zero known vulnerabilities after this
change.

Dev-only dep — strif's published wheel has zero runtime dependencies,
so this never reached end users.
@jlevy jlevy marked this pull request as ready for review May 23, 2026 05:14
Pre-release hardening: third-party GitHub Actions can be moved between
commits by re-pointing a major-version tag. Pinning to immutable SHAs
prevents that class of supply-chain attack on the publish pipeline.

Pinned (commented with the resolved tag for readability):
- actions/checkout@v6 -> @de0fac2e4500dabe0009e67214ff5f5447ce83dd  (v6.0.2)
- astral-sh/setup-uv@v7 -> @37802adc94f370d6bfd71619e3f0bf239e1f3b78  (v7.6.0)
- softprops/action-gh-release@v2 -> @3bb12739c298aeb8a4eeaf626c5b8d85266b0e65  (v2.6.2)

softprops/action-gh-release was the highest-priority target (single-
maintainer User repo, runs with `contents: write` in the workflow that
also has PyPI trusted publishing access). Comment added at the use site
to flag this and to remind future bumpers to update SHA + version
together.

When upgrading any of these later, get the new SHA via:
  gh api repos/<owner>/<repo>/git/ref/tags/<tag> --jq '.object.sha'

26 tests still pass.
@jlevy jlevy merged commit a59a269 into master May 23, 2026
5 checks passed
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.

2 participants