v2 restructure: Go client, Docker engine, release tooling
- Remove v1 Python CLI (src/kb_search/, tests/, root pyproject.toml, uv.lock, .venv) - Add Go client with cross-platform build (client/) - Add FastAPI engine with NVIDIA and multi-stage ROCm Dockerfiles (engine/) - Add VERSION files for client and engine, wired into builds - Add release.sh for automated build, tag, release, and Docker push - Update README with build/release docs and ROCm migration note - Clean up .gitignore for v2 project structure Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Executable
+268
@@ -0,0 +1,268 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# release.sh — Build, tag, and release kb-search
|
||||
#
|
||||
# Builds Go client binaries, Docker engine images, creates a Git tag + release,
|
||||
# and pushes container images to the registry.
|
||||
#
|
||||
# Usage:
|
||||
# ./release.sh # auto-increment patch, build, release
|
||||
# ./release.sh --no-increment # release using current VERSION files as-is
|
||||
# ./release.sh --dry-run # show what would happen without doing it
|
||||
# ./release.sh --minor # bump minor version (e.g. 2.0.1 → 2.1.0)
|
||||
# ./release.sh --major # bump major version (e.g. 2.1.0 → 3.0.0)
|
||||
# ./release.sh --gitea # use Gitea (tea) for release creation
|
||||
# ./release.sh --github # use GitHub (gh) for release creation
|
||||
#
|
||||
# One of --gitea or --github is required.
|
||||
# Assumes Docker is already authenticated to the registry.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
# Config
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
CLIENT_DIR="$SCRIPT_DIR/client"
|
||||
ENGINE_DIR="$SCRIPT_DIR/engine"
|
||||
|
||||
CLIENT_VERSION_FILE="$CLIENT_DIR/VERSION"
|
||||
ENGINE_VERSION_FILE="$ENGINE_DIR/VERSION"
|
||||
|
||||
# Container registry
|
||||
REGISTRY="${REGISTRY:-docker.dcglab.co.uk}"
|
||||
IMAGE_ORG="${IMAGE_ORG:-dcg}"
|
||||
IMAGE_BASE="${REGISTRY}/${IMAGE_ORG}/kb"
|
||||
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
# Parse args
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
DRY_RUN=false
|
||||
INCREMENT=true
|
||||
BUMP="patch"
|
||||
FORGE=""
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--dry-run) DRY_RUN=true ;;
|
||||
--no-increment) INCREMENT=false ;;
|
||||
--minor) BUMP="minor" ;;
|
||||
--major) BUMP="major" ;;
|
||||
--patch) BUMP="patch" ;;
|
||||
--gitea) FORGE="tea" ;;
|
||||
--github) FORGE="gh" ;;
|
||||
*)
|
||||
echo "Unknown argument: $arg"
|
||||
echo "Usage: $0 --gitea|--github [--dry-run] [--no-increment] [--patch|--minor|--major]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$FORGE" ]]; then
|
||||
echo "Error: specify --gitea or --github"
|
||||
echo "Usage: $0 --gitea|--github [--dry-run] [--no-increment] [--patch|--minor|--major]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v "$FORGE" &>/dev/null; then
|
||||
echo "Error: '$FORGE' not found in PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
# Version helpers
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
read_version() {
|
||||
local file="$1"
|
||||
if [[ ! -f "$file" ]]; then
|
||||
echo "Error: version file not found: $file" >&2
|
||||
exit 1
|
||||
fi
|
||||
tr -d '[:space:]' < "$file"
|
||||
}
|
||||
|
||||
bump_version() {
|
||||
local ver="$1" part="$2"
|
||||
local major minor patch
|
||||
IFS='.' read -r major minor patch <<< "$ver"
|
||||
|
||||
case "$part" in
|
||||
major) echo "$((major + 1)).0.0" ;;
|
||||
minor) echo "${major}.$((minor + 1)).0" ;;
|
||||
patch) echo "${major}.${minor}.$((patch + 1))" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
write_version() {
|
||||
local file="$1" ver="$2"
|
||||
echo "$ver" > "$file"
|
||||
}
|
||||
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
# Determine release version
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
CURRENT_VERSION="$(read_version "$CLIENT_VERSION_FILE")"
|
||||
|
||||
if [[ "$INCREMENT" == true ]]; then
|
||||
VERSION="$(bump_version "$CURRENT_VERSION" "$BUMP")"
|
||||
echo "==> Version bump: $CURRENT_VERSION → $VERSION ($BUMP)"
|
||||
else
|
||||
VERSION="$CURRENT_VERSION"
|
||||
echo "==> Version: $VERSION (no increment)"
|
||||
fi
|
||||
|
||||
TAG="v${VERSION}"
|
||||
|
||||
echo " Tag: $TAG"
|
||||
echo " Registry: $IMAGE_BASE"
|
||||
echo " Forge CLI: $FORGE"
|
||||
echo " Dry run: $DRY_RUN"
|
||||
echo ""
|
||||
|
||||
run() {
|
||||
echo " $ $*"
|
||||
if [[ "$DRY_RUN" == false ]]; then
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
# 1. Pre-flight checks
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
echo "==> Pre-flight checks"
|
||||
|
||||
if [[ "$DRY_RUN" == false ]]; then
|
||||
# Check tag doesn't already exist
|
||||
if git -C "$SCRIPT_DIR" rev-parse "$TAG" &>/dev/null; then
|
||||
echo "Error: tag $TAG already exists"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo " OK"
|
||||
echo ""
|
||||
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
# 2. Update version files
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
if [[ "$INCREMENT" == true ]]; then
|
||||
echo "==> Updating version files to $VERSION"
|
||||
run write_version "$CLIENT_VERSION_FILE" "$VERSION"
|
||||
run write_version "$ENGINE_VERSION_FILE" "$VERSION"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
# 3. Build Go client binaries
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
echo "==> Building Go client binaries ($VERSION)"
|
||||
|
||||
run make -C "$CLIENT_DIR" clean
|
||||
run make -C "$CLIENT_DIR" all VERSION="$VERSION"
|
||||
|
||||
# Collect release assets
|
||||
ASSETS=()
|
||||
if [[ "$DRY_RUN" == false ]]; then
|
||||
for bin in "$CLIENT_DIR"/dist/kb-*; do
|
||||
ASSETS+=("$bin")
|
||||
done
|
||||
echo " Built ${#ASSETS[@]} binaries"
|
||||
else
|
||||
echo " (skipped — dry run)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
# 4. Build Docker engine images
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
echo "==> Building Docker engine images ($VERSION)"
|
||||
|
||||
NVIDIA_IMAGE="${IMAGE_BASE}/engine:${TAG}-nvidia"
|
||||
ROCM_IMAGE="${IMAGE_BASE}/engine:${TAG}-rocm"
|
||||
NVIDIA_LATEST="${IMAGE_BASE}/engine:latest-nvidia"
|
||||
ROCM_LATEST="${IMAGE_BASE}/engine:latest-rocm"
|
||||
|
||||
run docker build -t "$NVIDIA_IMAGE" -t "$NVIDIA_LATEST" -f "$ENGINE_DIR/Dockerfile.nvidia" "$ENGINE_DIR"
|
||||
run docker build -t "$ROCM_IMAGE" -t "$ROCM_LATEST" -f "$ENGINE_DIR/Dockerfile.rocm" "$ENGINE_DIR"
|
||||
|
||||
echo ""
|
||||
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
# 5. Commit version bump, tag, and push
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
echo "==> Committing and tagging $TAG"
|
||||
|
||||
if [[ "$INCREMENT" == true ]]; then
|
||||
run git -C "$SCRIPT_DIR" add "$CLIENT_VERSION_FILE" "$ENGINE_VERSION_FILE"
|
||||
run git -C "$SCRIPT_DIR" commit -m "Bump version to $VERSION"
|
||||
fi
|
||||
|
||||
run git -C "$SCRIPT_DIR" tag -a "$TAG" -m "Release $TAG"
|
||||
run git -C "$SCRIPT_DIR" push origin HEAD
|
||||
run git -C "$SCRIPT_DIR" push origin "$TAG"
|
||||
|
||||
echo ""
|
||||
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
# 6. Create release with assets
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
echo "==> Creating release via $FORGE"
|
||||
|
||||
RELEASE_TITLE="$TAG"
|
||||
RELEASE_NOTES="## Docker images
|
||||
|
||||
\`\`\`bash
|
||||
# NVIDIA GPU
|
||||
docker pull ${NVIDIA_IMAGE}
|
||||
|
||||
# AMD GPU (ROCm)
|
||||
docker pull ${ROCM_IMAGE}
|
||||
\`\`\`
|
||||
|
||||
## Client binaries
|
||||
|
||||
Download the binary for your platform from the assets below, rename to \`kb\`, and place on your PATH."
|
||||
|
||||
if [[ "$FORGE" == "gh" ]]; then
|
||||
ASSET_FLAGS=()
|
||||
for f in "${ASSETS[@]+"${ASSETS[@]}"}"; do
|
||||
ASSET_FLAGS+=("$f")
|
||||
done
|
||||
run gh release create "$TAG" \
|
||||
--title "$RELEASE_TITLE" \
|
||||
--notes "$RELEASE_NOTES" \
|
||||
"${ASSET_FLAGS[@]+"${ASSET_FLAGS[@]}"}"
|
||||
|
||||
elif [[ "$FORGE" == "tea" ]]; then
|
||||
run tea release create \
|
||||
--tag "$TAG" \
|
||||
--title "$RELEASE_TITLE" \
|
||||
--note "$RELEASE_NOTES"
|
||||
|
||||
# tea attaches assets separately
|
||||
for f in "${ASSETS[@]+"${ASSETS[@]}"}"; do
|
||||
run tea release asset create --tag "$TAG" "$f"
|
||||
done
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
# 7. Push Docker images to registry
|
||||
#──────────────────────────────────────────────────────────────────────
|
||||
echo "==> Pushing Docker images to $REGISTRY"
|
||||
|
||||
run docker push "$NVIDIA_IMAGE"
|
||||
run docker push "$NVIDIA_LATEST"
|
||||
run docker push "$ROCM_IMAGE"
|
||||
run docker push "$ROCM_LATEST"
|
||||
|
||||
echo ""
|
||||
echo "==> Release $TAG complete!"
|
||||
echo ""
|
||||
echo " Images:"
|
||||
echo " $NVIDIA_IMAGE"
|
||||
echo " $ROCM_IMAGE"
|
||||
echo ""
|
||||
echo " Binaries: ${#ASSETS[@]} platform(s) attached to release"
|
||||
Reference in New Issue
Block a user