General-purpose coding policy for Baruch's AI agents
73
91%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
#!/usr/bin/env python3
"""Tests for skills/release/stamp-changelog.py — version computation and stamping."""
import importlib.util
import subprocess
import unittest
from unittest import mock
from pathlib import Path
SCRIPT = Path(__file__).resolve().parent.parent / "stamp-changelog.py"
spec = importlib.util.spec_from_file_location("stamp_changelog", SCRIPT)
assert spec and spec.loader, f"cannot load stamp-changelog.py at {SCRIPT}"
stamp_changelog = importlib.util.module_from_spec(spec)
spec.loader.exec_module(stamp_changelog)
_UNHEADED = """\
# Changelog
### feat(x) — new thing
Body of x.
### fix(y) — a bug
## 0.18.7 — 2026-06-03
### feat(prior) — already released
"""
class ComputeVersion(unittest.TestCase):
"""compute_version mirrors the publish step's --bump patch semantics."""
def test_first_publish_uses_local(self):
self.assertEqual(stamp_changelog.compute_version("0.1.0", None), "0.1.0")
def test_bumps_registry_patch(self):
self.assertEqual(stamp_changelog.compute_version("0.18.7", "0.18.7"), "0.18.8")
def test_bumps_registry_when_local_behind(self):
# Local manifest stale vs registry — still bump the registry patch.
self.assertEqual(stamp_changelog.compute_version("0.18.0", "0.18.7"), "0.18.8")
def test_respects_manual_ahead_bump(self):
# Local manifest deliberately ahead of registry — publish as-is.
self.assertEqual(stamp_changelog.compute_version("0.19.0", "0.18.7"), "0.19.0")
def test_rejects_malformed(self):
with self.assertRaises(ValueError):
stamp_changelog.compute_version("0.18", "0.18.7")
with self.assertRaises(ValueError):
stamp_changelog.compute_version("0.18.7", "vNext")
class Main(unittest.TestCase):
"""main() stamps the changelog with the version the publish step will assign."""
_BODY = "# Changelog\n\n### feat — x\n"
def _run(self, tmp, manifest_version, latest, body=None):
"""Run main() against a temp changelog/manifest; return the changelog text.
`latest=None` omits --latest and stubs the registry query to a 404
(first publish); a string passes --latest verbatim.
"""
changelog = tmp / "CHANGELOG.md"
changelog.write_text(body if body is not None else self._BODY)
manifest = tmp / "plugin.json"
manifest.write_text('{"name": "ws/p", "version": "%s"}' % manifest_version)
argv = [
"stamp-changelog.py",
"--changelog", str(changelog),
"--manifest", str(manifest),
"--date", "2026-08-09",
]
if latest is not None:
argv += ["--latest", latest]
with mock.patch("sys.argv", argv):
if latest is None:
with mock.patch.object(stamp_changelog, "query_latest_version",
return_value=None):
stamp_changelog.main()
else:
stamp_changelog.main()
return changelog.read_text()
def test_first_publish_stamps_manifest_version(self):
import tempfile
with tempfile.TemporaryDirectory() as d:
# No registry version → stamp the manifest version verbatim.
self.assertIn("## 0.1.0 — 2026-08-09", self._run(Path(d), "0.1.0", None))
def test_manifest_ahead_stamps_manifest_version(self):
import tempfile
with tempfile.TemporaryDirectory() as d:
self.assertIn("## 0.19.0 — 2026-08-09", self._run(Path(d), "0.19.0", "0.18.7"))
def test_normal_bump_stamps_bumped_version(self):
import tempfile
with tempfile.TemporaryDirectory() as d:
# Manifest matches registry → stamp the bumped patch.
self.assertIn("## 0.18.8 — 2026-08-09", self._run(Path(d), "0.18.7", "0.18.7"))
def test_noop_leaves_headed_changelog_unchanged(self):
import tempfile
with tempfile.TemporaryDirectory() as d:
# Top already headed → no stamp, changelog untouched.
already = "# Changelog\n\n## 0.1.0 — 2026-08-09\n\n### feat — x\n"
self.assertEqual(self._run(Path(d), "0.1.0", None, body=already), already)
class QueryLatestVersion(unittest.TestCase):
"""query_latest_version maps registry-version.sh's contract; failures raise."""
def _run(self, returncode, stdout="", stderr=""):
cp = subprocess.CompletedProcess(args=[], returncode=returncode, stdout=stdout, stderr=stderr)
with mock.patch.object(stamp_changelog.subprocess, "run", return_value=cp):
return stamp_changelog.query_latest_version("jbaruch/x")
def test_success_parses_latest(self):
self.assertEqual(self._run(0, stdout='{"version":"0.2.64"}\n'), "0.2.64")
def test_never_published_returns_none(self):
self.assertIsNone(self._run(0, stdout='{"version":null}\n'))
def test_404_raises(self):
# Never-published is {"version": null} on exit 0; a 404 is a tool failure.
with self.assertRaises(RuntimeError):
self._run(2, stderr="request failed: HTTP 404")
def test_auth_failure_raises(self):
msg = "✘ Please authenticate with Tessl to continue. Run `tessl login` to sign up or log in."
with self.assertRaises(RuntimeError):
self._run(2, stderr=msg)
def test_network_failure_raises(self):
with self.assertRaises(RuntimeError):
self._run(2, stderr="connection reset by peer")
_LAGGING_TESSL = """#!/usr/bin/env bash
set -euo pipefail
if [[ "$1" == "api" ]]; then
printf '%s' '{"data":[{"attributes":{"version":"0.3.269"}},{"attributes":{"version":"0.3.268"}}]}'
exit 0
fi
if [[ "$1" == "plugin" && "$2" == "info" ]]; then
printf 'Name ws/p\\nLatest Version 0.3.268\\n'
exit 0
fi
echo "unexpected tessl call: $*" >&2
exit 1
"""
class RegistryLag(unittest.TestCase):
"""The stamp reads the registry source smart-publish.sh publishes from (#606)."""
def test_stamps_from_versions_api_not_lagging_plugin_info(self):
import os
import tempfile
with tempfile.TemporaryDirectory() as d:
tmp = Path(d)
# Stub tessl: the plugin-info listing still shows the previous
# version while the versions API already has the just-published one.
stub = tmp / "tessl"
stub.write_text(_LAGGING_TESSL)
stub.chmod(0o755)
changelog = tmp / "CHANGELOG.md"
changelog.write_text("# Changelog\n\n### fix — y\n")
manifest = tmp / "plugin.json"
manifest.write_text('{"name": "ws/p", "version": "0.3.268"}')
env = dict(os.environ, PATH=f"{tmp}{os.pathsep}{os.environ['PATH']}")
proc = subprocess.run(
["python3", str(SCRIPT), "--changelog", str(changelog),
"--manifest", str(manifest), "--date", "2026-09-25"],
capture_output=True, text=True, env=env,
)
self.assertEqual(proc.returncode, 0, proc.stderr)
# smart-publish.sh publishes the versions-API latest plus one patch.
self.assertIn("## 0.3.270 — 2026-09-25", changelog.read_text())
class StampChangelog(unittest.TestCase):
"""stamp_changelog inserts a version heading above un-headed entries."""
def test_inserts_heading_above_unheaded_entries(self):
out, changed = stamp_changelog.stamp_changelog(_UNHEADED, "0.18.8", "2026-06-04")
self.assertTrue(changed)
lines = out.splitlines()
# Heading inserted directly above the first un-headed entry…
h_idx = lines.index("## 0.18.8 — 2026-06-04")
self.assertEqual(lines[h_idx + 2], "### feat(x) — new thing")
# …and above the prior released section, which is left intact.
self.assertLess(
lines.index("## 0.18.8 — 2026-06-04"),
lines.index("## 0.18.7 — 2026-06-03"),
)
self.assertIn("### feat(prior) — already released", out)
def test_noop_when_top_already_headed(self):
already = "# Changelog\n\n## 0.18.7 — 2026-06-03\n\n### feat(x) — released\n"
out, changed = stamp_changelog.stamp_changelog(already, "0.18.8", "2026-06-04")
self.assertFalse(changed)
self.assertEqual(out, already)
def test_noop_when_no_entries(self):
empty = "# Changelog\n"
out, changed = stamp_changelog.stamp_changelog(empty, "0.18.8", "2026-06-04")
self.assertFalse(changed)
self.assertEqual(out, empty)
def test_preserves_trailing_newline(self):
out, changed = stamp_changelog.stamp_changelog(_UNHEADED, "0.18.8", "2026-06-04")
self.assertTrue(changed)
self.assertTrue(out.endswith("\n"))
def test_idempotent(self):
once, _ = stamp_changelog.stamp_changelog(_UNHEADED, "0.18.8", "2026-06-04")
twice, changed = stamp_changelog.stamp_changelog(once, "0.18.9", "2026-06-05")
# Second run sees the heading already on top — no double stamp.
self.assertFalse(changed)
self.assertEqual(twice, once)
if __name__ == "__main__":
unittest.main().tessl-plugin
hooks
rules
skills
adopt-fork-pr
herdr-foreman
classify
foreman
references
templates
tests
herdr-standup
migrate-to-plugin
onboard-repo
release
references
tests