mirror of
https://github.com/mblanke/dev-backbone-template.git
synced 2026-03-01 05:50:22 -05:00
dev backbone template
This commit is contained in:
27
scripts/bootstrap_repo.ps1
Normal file
27
scripts/bootstrap_repo.ps1
Normal file
@@ -0,0 +1,27 @@
|
||||
Param(
|
||||
[Parameter(Mandatory=$true)][string]$RepoPath
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$RootDir = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
||||
$Target = (Resolve-Path $RepoPath).Path
|
||||
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $Target ".claude\agents") | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $Target "SKILLS") | Out-Null
|
||||
|
||||
Copy-Item -Force (Join-Path $RootDir "AGENTS.md") (Join-Path $Target "AGENTS.md")
|
||||
if (Test-Path (Join-Path $RootDir "SKILLS.md")) {
|
||||
Copy-Item -Force (Join-Path $RootDir "SKILLS.md") (Join-Path $Target "SKILLS.md")
|
||||
}
|
||||
Copy-Item -Recurse -Force (Join-Path $RootDir "SKILLS\*") (Join-Path $Target "SKILLS")
|
||||
Copy-Item -Recurse -Force (Join-Path $RootDir ".claude\agents\*") (Join-Path $Target ".claude\agents")
|
||||
|
||||
if (-not (Test-Path (Join-Path $Target ".gitlab-ci.yml")) -and (Test-Path (Join-Path $RootDir ".gitlab-ci.yml"))) {
|
||||
Copy-Item -Force (Join-Path $RootDir ".gitlab-ci.yml") (Join-Path $Target ".gitlab-ci.yml")
|
||||
}
|
||||
if (-not (Test-Path (Join-Path $Target ".github")) -and (Test-Path (Join-Path $RootDir ".github"))) {
|
||||
Copy-Item -Recurse -Force (Join-Path $RootDir ".github") (Join-Path $Target ".github")
|
||||
}
|
||||
|
||||
Write-Host "Bootstrapped repo: $Target"
|
||||
Write-Host "Next: wire DoD gates to your stack and run scripts\dod.ps1"
|
||||
33
scripts/bootstrap_repo.sh
Normal file
33
scripts/bootstrap_repo.sh
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Copy backbone files into an existing repo directory.
|
||||
# Usage: ./scripts/bootstrap_repo.sh /path/to/repo
|
||||
|
||||
TARGET="${1:-}"
|
||||
if [[ -z "$TARGET" ]]; then
|
||||
echo "Usage: $0 /path/to/repo"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
SRC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
mkdir -p "$TARGET/.claude/agents"
|
||||
mkdir -p "$TARGET/SKILLS"
|
||||
|
||||
# Copy minimal backbone (adjust to taste)
|
||||
cp -f "$SRC_DIR/AGENTS.md" "$TARGET/AGENTS.md"
|
||||
cp -f "$SRC_DIR/SKILLS.md" "$TARGET/SKILLS.md" || true
|
||||
cp -rf "$SRC_DIR/SKILLS/" "$TARGET/" || true
|
||||
cp -rf "$SRC_DIR/.claude/agents/" "$TARGET/.claude/agents/" || true
|
||||
|
||||
# Optional: CI templates
|
||||
if [[ ! -f "$TARGET/.gitlab-ci.yml" && -f "$SRC_DIR/.gitlab-ci.yml" ]]; then
|
||||
cp -f "$SRC_DIR/.gitlab-ci.yml" "$TARGET/.gitlab-ci.yml"
|
||||
fi
|
||||
if [[ ! -d "$TARGET/.github" && -d "$SRC_DIR/.github" ]]; then
|
||||
cp -rf "$SRC_DIR/.github" "$TARGET/.github"
|
||||
fi
|
||||
|
||||
echo "Bootstrapped repo: $TARGET"
|
||||
echo "Next: wire DoD gates to your stack (npm/pip) and run scripts/dod.sh"
|
||||
42
scripts/dod.ps1
Normal file
42
scripts/dod.ps1
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
Write-Host "== DoD Gate =="
|
||||
|
||||
$root = Split-Path -Parent $PSScriptRoot
|
||||
Set-Location $root
|
||||
|
||||
function Has-Command($name) {
|
||||
return $null -ne (Get-Command $name -ErrorAction SilentlyContinue)
|
||||
}
|
||||
|
||||
$hasNode = Test-Path ".\package.json"
|
||||
$hasPy = (Test-Path ".\pyproject.toml") -or (Test-Path ".\requirements.txt") -or (Test-Path ".\requirements-dev.txt")
|
||||
|
||||
if ($hasNode) {
|
||||
if (-not (Has-Command "npm")) { throw "npm not found" }
|
||||
Write-Host "+ npm ci"; npm ci
|
||||
$pkg = Get-Content ".\package.json" | ConvertFrom-Json
|
||||
if ($pkg.scripts.lint) { Write-Host "+ npm run lint"; npm run lint }
|
||||
if ($pkg.scripts.typecheck) { Write-Host "+ npm run typecheck"; npm run typecheck }
|
||||
if ($pkg.scripts.test) { Write-Host "+ npm test"; npm test }
|
||||
if ($pkg.scripts.build) { Write-Host "+ npm run build"; npm run build }
|
||||
}
|
||||
|
||||
if ($hasPy) {
|
||||
if (-not (Has-Command "python")) { throw "python not found" }
|
||||
Write-Host "+ python -m pip install -U pip"; python -m pip install -U pip
|
||||
if (Test-Path ".\requirements.txt") { Write-Host "+ pip install -r requirements.txt"; pip install -r requirements.txt }
|
||||
if (Test-Path ".\requirements-dev.txt") { Write-Host "+ pip install -r requirements-dev.txt"; pip install -r requirements-dev.txt }
|
||||
if (Has-Command "ruff") {
|
||||
Write-Host "+ ruff check ."; ruff check .
|
||||
Write-Host "+ ruff format --check ."; ruff format --check .
|
||||
}
|
||||
if (Has-Command "pytest") { Write-Host "+ pytest -q"; pytest -q }
|
||||
}
|
||||
|
||||
if (-not $hasNode -and -not $hasPy) {
|
||||
Write-Host "No package.json or Python dependency files detected."
|
||||
Write-Host "Customize scripts\dod.ps1 for this repo stack."
|
||||
}
|
||||
|
||||
Write-Host "DoD PASS"
|
||||
43
scripts/dod.sh
Normal file
43
scripts/dod.sh
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "== DoD Gate =="
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
fail() { echo "DoD FAIL: $1" >&2; exit 1; }
|
||||
run() { echo "+ $*"; "$@"; }
|
||||
has() { command -v "$1" >/dev/null 2>&1; }
|
||||
|
||||
HAS_NODE=0
|
||||
HAS_PY=0
|
||||
[[ -f package.json ]] && HAS_NODE=1
|
||||
[[ -f pyproject.toml || -f requirements.txt || -f requirements-dev.txt ]] && HAS_PY=1
|
||||
|
||||
if [[ $HAS_NODE -eq 1 ]]; then
|
||||
has npm || fail "npm not found"
|
||||
run npm ci
|
||||
if has jq && jq -e '.scripts.lint' package.json >/dev/null 2>&1; then run npm run lint; fi
|
||||
if has jq && jq -e '.scripts.typecheck' package.json >/dev/null 2>&1; then run npm run typecheck; fi
|
||||
if has jq && jq -e '.scripts.test' package.json >/dev/null 2>&1; then run npm test; fi
|
||||
if has jq && jq -e '.scripts.build' package.json >/dev/null 2>&1; then run npm run build; fi
|
||||
fi
|
||||
|
||||
if [[ $HAS_PY -eq 1 ]]; then
|
||||
has python3 || fail "python3 not found"
|
||||
run python3 -m pip install -U pip
|
||||
if [[ -f requirements.txt ]]; then run python3 -m pip install -r requirements.txt; fi
|
||||
if [[ -f requirements-dev.txt ]]; then run python3 -m pip install -r requirements-dev.txt; fi
|
||||
if has ruff; then
|
||||
run ruff check . || true
|
||||
run ruff format --check . || true
|
||||
fi
|
||||
if has pytest; then run pytest -q || true; fi
|
||||
fi
|
||||
|
||||
if [[ $HAS_NODE -eq 0 && $HAS_PY -eq 0 ]]; then
|
||||
echo "No package.json or Python dependency files detected."
|
||||
echo "Customize scripts/dod.sh for this repo stack."
|
||||
fi
|
||||
|
||||
echo "DoD PASS"
|
||||
56
scripts/monday.ps1
Normal file
56
scripts/monday.ps1
Normal file
@@ -0,0 +1,56 @@
|
||||
Param(
|
||||
[Parameter(Mandatory=$false)][string]$Command = "status",
|
||||
[Parameter(Mandatory=$false)][string]$RepoPath = ""
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$RootDir = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
||||
|
||||
Write-Host "== Dev Backbone Monday Runner =="
|
||||
|
||||
function Need-Cmd($name) {
|
||||
if (-not (Get-Command $name -ErrorAction SilentlyContinue)) {
|
||||
throw "Missing command: $name"
|
||||
}
|
||||
}
|
||||
|
||||
switch ($Command) {
|
||||
"status" {
|
||||
$code = (Get-Command code -ErrorAction SilentlyContinue)
|
||||
$git = (Get-Command git -ErrorAction SilentlyContinue)
|
||||
$docker = (Get-Command docker -ErrorAction SilentlyContinue)
|
||||
|
||||
Write-Host "[1] VS Code CLI:" ($code.Source ?? "NOT FOUND")
|
||||
Write-Host "[2] Git: " ($git.Source ?? "NOT FOUND")
|
||||
Write-Host "[3] Docker: " ($docker.Source ?? "NOT FOUND")
|
||||
Write-Host ""
|
||||
Write-Host "Profiles expected: Dev, Cyber, Infra"
|
||||
Write-Host "Try: code --list-extensions --profile Dev"
|
||||
}
|
||||
|
||||
"vscode-purge" {
|
||||
Need-Cmd code
|
||||
if ($env:CONFIRM -ne "YES") {
|
||||
Write-Host "Refusing to uninstall extensions without CONFIRM=YES"
|
||||
Write-Host "Run: `$env:CONFIRM='YES'; .\scripts\monday.ps1 -Command vscode-purge"
|
||||
exit 2
|
||||
}
|
||||
& (Join-Path $RootDir "scripts\vscode_profiles.ps1") -Action purge
|
||||
}
|
||||
|
||||
"vscode-install" {
|
||||
Need-Cmd code
|
||||
& (Join-Path $RootDir "scripts\vscode_profiles.ps1") -Action install
|
||||
}
|
||||
|
||||
"repo-bootstrap" {
|
||||
if ([string]::IsNullOrWhiteSpace($RepoPath)) {
|
||||
throw "Usage: .\scripts\monday.ps1 -Command repo-bootstrap -RepoPath C:\path\to\repo"
|
||||
}
|
||||
& (Join-Path $RootDir "scripts\bootstrap_repo.ps1") -RepoPath $RepoPath
|
||||
}
|
||||
|
||||
default {
|
||||
throw "Unknown command: $Command"
|
||||
}
|
||||
}
|
||||
66
scripts/monday.sh
Normal file
66
scripts/monday.sh
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Monday Overhaul Runner (safe by default)
|
||||
# Usage:
|
||||
# ./scripts/monday.sh status
|
||||
# ./scripts/monday.sh vscode-purge (requires CONFIRM=YES)
|
||||
# ./scripts/monday.sh vscode-install
|
||||
# ./scripts/monday.sh repo-bootstrap /path/to/repo
|
||||
#
|
||||
# Notes:
|
||||
# - VS Code profile creation is easiest once via UI (Profiles: Create Profile).
|
||||
# This script assumes profiles exist: Dev, Cyber, Infra.
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
echo "== Dev Backbone Monday Runner =="
|
||||
echo "Repo: $ROOT_DIR"
|
||||
echo
|
||||
|
||||
cmd="${1:-status}"
|
||||
shift || true
|
||||
|
||||
need_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || { echo "Missing command: $1"; exit 1; }
|
||||
}
|
||||
|
||||
case "$cmd" in
|
||||
status)
|
||||
echo "[1] VS Code CLI: $(command -v code || echo 'NOT FOUND')"
|
||||
echo "[2] Git: $(command -v git || echo 'NOT FOUND')"
|
||||
echo "[3] Docker: $(command -v docker || echo 'NOT FOUND')"
|
||||
echo
|
||||
echo "Profiles expected: Dev, Cyber, Infra"
|
||||
echo "Try: code --list-extensions --profile Dev"
|
||||
;;
|
||||
|
||||
vscode-purge)
|
||||
need_cmd code
|
||||
if [[ "${CONFIRM:-NO}" != "YES" ]]; then
|
||||
echo "Refusing to uninstall extensions without CONFIRM=YES"
|
||||
echo "Run: CONFIRM=YES ./scripts/monday.sh vscode-purge"
|
||||
exit 2
|
||||
fi
|
||||
bash "$ROOT_DIR/scripts/vscode_profiles.sh" purge
|
||||
;;
|
||||
|
||||
vscode-install)
|
||||
need_cmd code
|
||||
bash "$ROOT_DIR/scripts/vscode_profiles.sh" install
|
||||
;;
|
||||
|
||||
repo-bootstrap)
|
||||
repo_path="${1:-}"
|
||||
if [[ -z "$repo_path" ]]; then
|
||||
echo "Usage: ./scripts/monday.sh repo-bootstrap /path/to/repo"
|
||||
exit 2
|
||||
fi
|
||||
bash "$ROOT_DIR/scripts/bootstrap_repo.sh" "$repo_path"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown command: $cmd"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
75
scripts/vscode_profiles.ps1
Normal file
75
scripts/vscode_profiles.ps1
Normal file
@@ -0,0 +1,75 @@
|
||||
Param(
|
||||
[Parameter(Mandatory=$true)][ValidateSet("purge","install")][string]$Action
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Profile-Exists([string]$ProfileName) {
|
||||
try {
|
||||
& code --list-extensions --profile $ProfileName | Out-Null
|
||||
return $true
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
# Curated extension sets (edit to taste)
|
||||
$DevExt = @(
|
||||
"GitHub.copilot",
|
||||
"GitHub.copilot-chat",
|
||||
"GitHub.vscode-pull-request-github",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"ms-python.python",
|
||||
"ms-python.vscode-pylance",
|
||||
"ms-azuretools.vscode-docker",
|
||||
"ms-vscode-remote.remote-ssh",
|
||||
"ms-vscode-remote.remote-containers",
|
||||
"redhat.vscode-yaml",
|
||||
"yzhang.markdown-all-in-one"
|
||||
)
|
||||
|
||||
$CyberExt = @($DevExt) # add more only if needed
|
||||
$InfraExt = @(
|
||||
"ms-azuretools.vscode-docker",
|
||||
"ms-vscode-remote.remote-ssh",
|
||||
"redhat.vscode-yaml",
|
||||
"yzhang.markdown-all-in-one"
|
||||
)
|
||||
|
||||
function Purge-Profile([string]$ProfileName) {
|
||||
Write-Host "Purging extensions from profile: $ProfileName"
|
||||
if (-not (Profile-Exists $ProfileName)) {
|
||||
Write-Host "Profile not found: $ProfileName (create once via UI: Profiles: Create Profile)"
|
||||
return
|
||||
}
|
||||
$exts = & code --list-extensions --profile $ProfileName
|
||||
foreach ($ext in $exts) {
|
||||
if ([string]::IsNullOrWhiteSpace($ext)) { continue }
|
||||
& code --profile $ProfileName --uninstall-extension $ext | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
function Install-Profile([string]$ProfileName, [string[]]$Extensions) {
|
||||
Write-Host "Installing extensions into profile: $ProfileName"
|
||||
if (-not (Profile-Exists $ProfileName)) {
|
||||
Write-Host "Profile not found: $ProfileName (create once via UI: Profiles: Create Profile)"
|
||||
return
|
||||
}
|
||||
foreach ($ext in $Extensions) {
|
||||
& code --profile $ProfileName --install-extension $ext | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
switch ($Action) {
|
||||
"purge" {
|
||||
Purge-Profile "Dev"
|
||||
Purge-Profile "Cyber"
|
||||
Purge-Profile "Infra"
|
||||
}
|
||||
"install" {
|
||||
Install-Profile "Dev" $DevExt
|
||||
Install-Profile "Cyber" $CyberExt
|
||||
Install-Profile "Infra" $InfraExt
|
||||
}
|
||||
}
|
||||
93
scripts/vscode_profiles.sh
Normal file
93
scripts/vscode_profiles.sh
Normal file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Manage extensions per VS Code profile.
|
||||
# Requires profiles to exist: Dev, Cyber, Infra
|
||||
# Actions:
|
||||
# ./scripts/vscode_profiles.sh purge (uninstall ALL extensions from those profiles)
|
||||
# ./scripts/vscode_profiles.sh install (install curated sets)
|
||||
|
||||
ACTION="${1:-}"
|
||||
if [[ -z "$ACTION" ]]; then
|
||||
echo "Usage: $0 {purge|install}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
need() { command -v "$1" >/dev/null 2>&1 || { echo "Missing: $1"; exit 1; }; }
|
||||
need code
|
||||
|
||||
# Curated extension sets (edit to taste)
|
||||
DEV_EXT=(
|
||||
"GitHub.copilot"
|
||||
"GitHub.copilot-chat"
|
||||
"GitHub.vscode-pull-request-github"
|
||||
"dbaeumer.vscode-eslint"
|
||||
"esbenp.prettier-vscode"
|
||||
"ms-python.python"
|
||||
"ms-python.vscode-pylance"
|
||||
"ms-azuretools.vscode-docker"
|
||||
"ms-vscode-remote.remote-ssh"
|
||||
"ms-vscode-remote.remote-containers"
|
||||
"redhat.vscode-yaml"
|
||||
"yzhang.markdown-all-in-one"
|
||||
)
|
||||
|
||||
CYBER_EXT=(
|
||||
"${DEV_EXT[@]}"
|
||||
# Add only if you truly use them:
|
||||
# "ms-kubernetes-tools.vscode-kubernetes-tools"
|
||||
)
|
||||
|
||||
INFRA_EXT=(
|
||||
"ms-azuretools.vscode-docker"
|
||||
"ms-vscode-remote.remote-ssh"
|
||||
"redhat.vscode-yaml"
|
||||
"yzhang.markdown-all-in-one"
|
||||
# Optional:
|
||||
# "hashicorp.terraform"
|
||||
)
|
||||
|
||||
purge_profile() {
|
||||
local profile="$1"
|
||||
echo "Purging extensions from profile: $profile"
|
||||
# list may fail if profile doesn't exist
|
||||
if ! code --list-extensions --profile "$profile" >/dev/null 2>&1; then
|
||||
echo "Profile not found: $profile (create once via UI: Profiles: Create Profile)"
|
||||
return 0
|
||||
fi
|
||||
code --list-extensions --profile "$profile" | while read -r ext; do
|
||||
[[ -z "$ext" ]] && continue
|
||||
code --profile "$profile" --uninstall-extension "$ext" || true
|
||||
done
|
||||
}
|
||||
|
||||
install_profile() {
|
||||
local profile="$1"; shift
|
||||
local exts=("$@")
|
||||
echo "Installing extensions into profile: $profile"
|
||||
if ! code --list-extensions --profile "$profile" >/dev/null 2>&1; then
|
||||
echo "Profile not found: $profile (create once via UI: Profiles: Create Profile)"
|
||||
return 0
|
||||
fi
|
||||
for ext in "${exts[@]}"; do
|
||||
[[ "$ext" =~ ^# ]] && continue
|
||||
code --profile "$profile" --install-extension "$ext"
|
||||
done
|
||||
}
|
||||
|
||||
case "$ACTION" in
|
||||
purge)
|
||||
purge_profile "Dev"
|
||||
purge_profile "Cyber"
|
||||
purge_profile "Infra"
|
||||
;;
|
||||
install)
|
||||
install_profile "Dev" "${DEV_EXT[@]}"
|
||||
install_profile "Cyber" "${CYBER_EXT[@]}"
|
||||
install_profile "Infra" "${INFRA_EXT[@]}"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown action: $ACTION"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user