feat(kb): brain tools, Go async serve, root-level docker
- tools/kblib.py: ladybug schema, embeddings, FTS+vector, hybrid RRF
- bin/kb/{index,search,get,stats,eval}: corpus indexing + deduction search
- bin/facts/{extract,audit}: 2-source evidence acquisition + gates
- serve/: async Go HTTP server (goroutines, bounded worker pool), TDD
- docker/ flattened to root: compose.yaml + Dockerfile (multi-stage Go)
- docker scripts -> bin/ shebang pattern (kb-watch, docker-entrypoint)
- bin/ci/semver + tools/semver.py: conventional-commit semver release
- ci.yml: go tests + shell checks; drop release-please (PR toggle blocked)
This commit is contained in:
Executable
+53
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python3
|
||||
"""ci/semver - next semver from conventional commits since the last tag.
|
||||
|
||||
bin/ci/semver # last tag..HEAD
|
||||
bin/ci/semver v0.1.0 v0.1.0..HEAD # explicit tag + range
|
||||
prints: v0.1.1 | v0.2.0 | v1.0.0 | none
|
||||
|
||||
Bump rules (conventional commits):
|
||||
BREAKING CHANGE / feat! -> major
|
||||
feat: -> minor
|
||||
fix:, perf:, refactor:,... -> patch
|
||||
no commits in range -> none
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "tools"))
|
||||
|
||||
from semver import bump_type, bump_version # noqa: E402
|
||||
|
||||
|
||||
def subjects_for(range_: str) -> list[str]:
|
||||
args = ["git", "log", "--format=%s"]
|
||||
if range_ and range_ != "HEAD":
|
||||
args.append(range_)
|
||||
try:
|
||||
out = subprocess.run(args, capture_output=True, text=True, check=True).stdout
|
||||
except subprocess.CalledProcessError:
|
||||
return []
|
||||
return [line.strip() for line in out.splitlines() if line.strip()]
|
||||
|
||||
|
||||
def last_tag() -> str | None:
|
||||
try:
|
||||
out = subprocess.run(["git", "tag", "--sort=-v:refname"], capture_output=True, text=True, check=True).stdout
|
||||
tags = [t.strip() for t in out.splitlines() if t.strip().startswith("v")]
|
||||
return tags[0] if tags else None
|
||||
except subprocess.CalledProcessError:
|
||||
return None
|
||||
|
||||
|
||||
def main(argv: list[str]) -> int:
|
||||
tag = argv[1] if len(argv) > 1 else last_tag()
|
||||
range_ = argv[2] if len(argv) > 2 else (f"{tag}..HEAD" if tag else "HEAD")
|
||||
print(bump_version(tag, bump_type(subjects_for(range_))) or "none")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main(sys.argv))
|
||||
Reference in New Issue
Block a user