diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..6bd82a9 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,23 @@ +## Summary + +## Changes + +- + +## Type of Change + +- [ ] `feat` — New feature +- [ ] `fix` — Bug fix +- [ ] `perf` — Performance improvement +- [ ] `refactor` — Code refactor (no behavior change) +- [ ] `chore` — Build, tooling, dependencies +- [ ] `docs` — Documentation only +- [ ] `ci` — CI/CD changes +- [ ] `BREAKING CHANGE` — Incompatible API change + +## Checklist + +- [ ] Code builds without errors (`go build ./...` / `bun run build`) +- [ ] Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/) +- [ ] `.env.example` updated if new environment variables were added +- [ ] API documentation updated if endpoints changed diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e69de29 diff --git a/backend/config/version.go b/backend/config/version.go new file mode 100644 index 0000000..c5e411a --- /dev/null +++ b/backend/config/version.go @@ -0,0 +1,4 @@ +// Code generated by scripts/release.sh — DO NOT EDIT. +package config + +const Version = "1.0.0" diff --git a/package.json b/package.json index e1a212f..5f48989 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,10 @@ "description": "🧘‍♂️ ZenReply: Protect Your Deep Work", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", + "release:patch": "bash scripts/release.sh patch", + "release:minor": "bash scripts/release.sh minor", + "release:major": "bash scripts/release.sh major", + "release": "bash scripts/release.sh", "prepare": "husky" }, "repository": { diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 0000000..4999ffe --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,157 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +BOLD='\033[1m' +NC='\033[0m' + +log_info() { echo -e "${BLUE}ℹ${NC} $*"; } +log_success() { echo -e "${GREEN}✓${NC} $*"; } +log_warn() { echo -e "${YELLOW}⚠${NC} $*"; } +log_error() { echo -e "${RED}✗${NC} $*" >&2; } + +# Helpers +require_command() { + if ! command -v "$1" &>/dev/null; then + log_error "Required command not found: $1" + exit 1 + fi +} + +require_command git +require_command node + +# Validate working directory +cd "$ROOT_DIR" + +if [[ ! -f "package.json" ]]; then + log_error "Must be run from the ZenReply root directory." + exit 1 +fi + +# Check for uncommitted changes +if [[ -n "$(git status --porcelain)" ]]; then + log_error "Working directory is not clean. Commit or stash changes first." + git status --short + exit 1 +fi + +# Determine current version +CURRENT_VERSION=$(node -p "require('./package.json').version") +log_info "Current version: ${BOLD}${CURRENT_VERSION}${NC}" + +# Parse bump type or explicit version +BUMP="${1:-}" + +if [[ -z "$BUMP" ]]; then + log_error "Usage: $0 " + exit 1 +fi + +bump_semver() { + local version="$1" + local part="$2" + IFS='.' read -r major minor patch <<< "$version" + case "$part" in + major) echo "$((major + 1)).0.0" ;; + minor) echo "${major}.$((minor + 1)).0" ;; + patch) echo "${major}.${minor}.$((patch + 1))" ;; + *) echo "$part" ;; # explicit version + esac +} + +NEW_VERSION=$(bump_semver "$CURRENT_VERSION" "$BUMP") + +# Validate semver format +if ! [[ "$NEW_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then + log_error "Invalid version format: $NEW_VERSION (expected: x.y.z or x.y.z-rc.1)" + exit 1 +fi + +log_info "New version: ${BOLD}${NEW_VERSION}${NC}" +echo "" + +# ── Confirm ─────────────────────────────────────────────────── +read -rp "$(echo -e "${YELLOW}?${NC} Bump ${CURRENT_VERSION} → ${NEW_VERSION} and push tag? [y/N] ")" confirm +if [[ "${confirm,,}" != "y" ]]; then + log_warn "Aborted." + exit 0 +fi + +echo "" + +# Step 1: Update root package.json +log_info "Updating root package.json..." +node -e " + const fs = require('fs'); + const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); + pkg.version = '${NEW_VERSION}'; + fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n'); +" +log_success "package.json → ${NEW_VERSION}" + +# Step 2: Update frontend/package.json +if [[ -f "frontend/package.json" ]]; then + log_info "Updating frontend/package.json..." + node -e " + const fs = require('fs'); + const pkg = JSON.parse(fs.readFileSync('frontend/package.json', 'utf8')); + pkg.version = '${NEW_VERSION}'; + fs.writeFileSync('frontend/package.json', JSON.stringify(pkg, null, 2) + '\n'); + " + log_success "frontend/package.json → ${NEW_VERSION}" +fi + +# Step 3: Update backend version constant +log_info "Updating backend/config/version.go..." +cat > "backend/config/version.go" << EOF +// Code generated by scripts/release.sh — DO NOT EDIT. +package config + +const Version = "${NEW_VERSION}" +EOF +log_success "backend/config/version.go → ${NEW_VERSION}" + +# Step 4: Git commit +log_info "Committing version bump..." +git add \ + package.json \ + frontend/package.json \ + backend/config/version.go + +git commit -m "chore(release): v${NEW_VERSION} + +Bump version across all packages: +- package.json: ${CURRENT_VERSION} → ${NEW_VERSION} +- frontend/package.json: ${CURRENT_VERSION} → ${NEW_VERSION} +- backend/config/version.go: ${CURRENT_VERSION} → ${NEW_VERSION}" + +log_success "Committed: chore(release): v${NEW_VERSION}" + +# Step 5: Create annotated Git tag +log_info "Creating tag v${NEW_VERSION}..." +git tag -a "v${NEW_VERSION}" -m "Release v${NEW_VERSION}" +log_success "Tag created: v${NEW_VERSION}" + +# Step 6: Push commit + tag +log_info "Pushing to origin..." +git push origin main +git push origin "v${NEW_VERSION}" +log_success "Pushed commit and tag to origin" + +echo "" +echo -e "${GREEN}${BOLD} Release v${NEW_VERSION} triggered!${NC}" +echo "" +echo -e " GitHub Actions will now:" +echo -e " ${BLUE}1.${NC} Build Docker image (linux/amd64 + linux/arm64)" +echo -e " ${BLUE}2.${NC} Push to ghcr.io with tags: ${NEW_VERSION}, latest" +echo -e " ${BLUE}3.${NC} Create GitHub Release with auto-generated notes" +echo "" +echo -e " Track progress: ${BLUE}https://github.com/blogic-kietle/ZenReply/actions${NC}"