Skip to content
This repository was archived by the owner on Jul 9, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .claims/claims.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"claims": []
}
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Copy to .env and fill values
APP_ENV=development
PORT=3000
49 changes: 49 additions & 0 deletions .github/workflows/standard-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Standard CI

on:
pull_request:
push:
branches: [main, master, develop]

jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
if: ${{ hashFiles('package.json') != '' }}
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Setup Python
if: ${{ hashFiles('requirements.txt') != '' }}
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install Node deps
if: ${{ hashFiles('package.json') != '' }}
run: |
npm install -g pnpm || true
if [ -f pnpm-lock.yaml ]; then pnpm install --frozen-lockfile; else npm ci || npm install; fi

- name: Install Python deps
if: ${{ hashFiles('requirements.txt') != '' }}
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pytest || true

- name: Validate Claims JSON
run: |
if [ -f .claims/claims.json ]; then
jq . .claims/claims.json >/dev/null
fi

- name: Run tests
run: |
chmod +x scripts/test.sh || true
if [ -f scripts/test.sh ]; then ./scripts/test.sh; else echo "No scripts/test.sh"; fi
7 changes: 7 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Default owners. Replace with your team handles.
* @OWNER_PLACEHOLDER

# Example ownership split (edit per repo)
# /frontend/ @frontend-owner
# /backend/ @backend-owner
# /infra/ @platform-owner
23 changes: 23 additions & 0 deletions scripts/check-env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail

required=(APP_ENV)

if [[ -f .env ]]; then
# shellcheck disable=SC1091
source .env
fi

missing=()
for key in "${required[@]}"; do
if [[ -z "${!key:-}" ]]; then
missing+=("$key")
fi
done

if (( ${#missing[@]} > 0 )); then
echo "Missing required env vars: ${missing[*]}" >&2
exit 1
fi

echo "Environment looks good"
137 changes: 137 additions & 0 deletions scripts/claim.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#!/usr/bin/env bash
set -euo pipefail

CLAIMS_FILE=".claims/claims.json"
DEFAULT_TTL_HOURS="4"

usage() {
cat <<USAGE
Usage:
scripts/claim.sh claim <owner> <path> [ttl_hours]
scripts/claim.sh release <owner> <path>
scripts/claim.sh status [path]
scripts/claim.sh prune

Examples:
scripts/claim.sh claim dev1 src/api 4
scripts/claim.sh release dev1 src/api
scripts/claim.sh status src
USAGE
}

require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "Missing required command: $1" >&2
exit 1
}
}

now_epoch() {
date +%s
}

ensure_store() {
mkdir -p "$(dirname "$CLAIMS_FILE")"
if [[ ! -f "$CLAIMS_FILE" ]]; then
cat > "$CLAIMS_FILE" <<JSON
{"claims":[]}
JSON
fi
}

prune_expired() {
local now
now="$(now_epoch)"
tmp="$(mktemp)"
jq --argjson now "$now" '.claims |= map(select(.expires_at > $now))' "$CLAIMS_FILE" > "$tmp"
mv "$tmp" "$CLAIMS_FILE"
}

claim_path() {
local owner="$1"
local path="$2"
local ttl_hours="${3:-$DEFAULT_TTL_HOURS}"
local now expires

now="$(now_epoch)"
expires="$(( now + ttl_hours * 3600 ))"

prune_expired

local conflict
conflict="$(jq -r --arg p "$path" --arg o "$owner" '
.claims[]
| select(.owner != $o)
| select((.path | startswith($p)) or ($p | startswith(.path)))
| "\(.owner)|\(.path)|\(.expires_at)"
' "$CLAIMS_FILE" | head -n1 || true)"

if [[ -n "$conflict" ]]; then
IFS='|' read -r c_owner c_path c_exp <<<"$conflict"
echo "Claim conflict: '$path' overlaps claim by '$c_owner' on '$c_path' (expires_at=$c_exp)" >&2
exit 2
fi

tmp="$(mktemp)"
jq --arg o "$owner" --arg p "$path" --argjson n "$now" --argjson e "$expires" '
.claims += [{"owner":$o,"path":$p,"claimed_at":$n,"expires_at":$e}]
' "$CLAIMS_FILE" > "$tmp"
mv "$tmp" "$CLAIMS_FILE"

echo "Claimed: owner=$owner path=$path ttl_hours=$ttl_hours"
}

release_path() {
local owner="$1"
local path="$2"

tmp="$(mktemp)"
jq --arg o "$owner" --arg p "$path" '
.claims |= map(select(.owner != $o or .path != $p))
' "$CLAIMS_FILE" > "$tmp"
mv "$tmp" "$CLAIMS_FILE"

echo "Released: owner=$owner path=$path"
}

status_claims() {
local path="${1:-}"
prune_expired

if [[ -z "$path" ]]; then
jq '.claims' "$CLAIMS_FILE"
return
fi

jq --arg p "$path" '.claims | map(select((.path | startswith($p)) or ($p | startswith(.path))))' "$CLAIMS_FILE"
}

main() {
require_cmd jq
ensure_store

cmd="${1:-}"
case "$cmd" in
claim)
[[ $# -ge 3 ]] || { usage; exit 1; }
claim_path "$2" "$3" "${4:-$DEFAULT_TTL_HOURS}"
;;
release)
[[ $# -ge 3 ]] || { usage; exit 1; }
release_path "$2" "$3"
;;
status)
status_claims "${2:-}"
;;
prune)
prune_expired
echo "Pruned expired claims"
;;
*)
usage
exit 1
;;
esac
}

main "$@"
15 changes: 15 additions & 0 deletions scripts/e2e.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail

echo "[e2e] Running end-to-end checks"

if [[ -f package.json ]]; then
if command -v pnpm >/dev/null 2>&1; then
pnpm run e2e
else
npm run e2e
fi
exit 0
fi

echo "[e2e] No e2e runner configured"
8 changes: 8 additions & 0 deletions scripts/preflight-claim.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail

OWNER="${1:-${USER:-unknown}}"
TARGET="${2:-.}"
TTL_HOURS="${3:-4}"

./scripts/claim.sh claim "$OWNER" "$TARGET" "$TTL_HOURS"
29 changes: 29 additions & 0 deletions scripts/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -euo pipefail

echo "[setup] Starting project setup"

if [[ -f package.json ]]; then
if command -v pnpm >/dev/null 2>&1; then
pnpm install
elif command -v npm >/dev/null 2>&1; then
npm install
else
echo "[setup][error] node package manager not found" >&2
exit 1
fi
fi

if [[ -f requirements.txt ]]; then
if [[ ! -d .venv ]]; then
python3 -m venv .venv
fi
# shellcheck disable=SC1091
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
fi

./scripts/check-env.sh || true

echo "[setup] Done"
24 changes: 24 additions & 0 deletions scripts/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -euo pipefail

echo "[start] Starting app"

if [[ -f package.json ]]; then
if command -v pnpm >/dev/null 2>&1; then
exec pnpm start
else
exec npm start
fi
fi

if [[ -f app.py ]]; then
if [[ -d .venv ]]; then
# shellcheck disable=SC1091
source .venv/bin/activate
fi
export FLASK_APP=app.py
exec flask run --host 0.0.0.0 --port "${PORT:-5000}"
fi

echo "[start][error] No known app entrypoint found" >&2
exit 1
24 changes: 24 additions & 0 deletions scripts/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -euo pipefail

echo "[test] Running unit/integration tests"

if [[ -f package.json ]]; then
if command -v pnpm >/dev/null 2>&1; then
pnpm test
else
npm test
fi
exit 0
fi

if compgen -G "tests/*.py" >/dev/null || compgen -G "test_*.py" >/dev/null; then
if [[ -d .venv ]]; then
# shellcheck disable=SC1091
source .venv/bin/activate
fi
python -m pytest
exit 0
fi

echo "[test] No tests detected"
Loading