From 505b956bfdeeccb4abb2bf5c343b5973c6d411f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Den=20Delimarsky=20=F0=9F=8C=BA?= <53200638+localden@users.noreply.github.com> Date: Sat, 20 Sep 2025 12:14:42 -0700 Subject: [PATCH] Script cleanup --- scripts/bash/common.sh | 48 ++++++++++++++-- scripts/bash/setup-plan.sh | 57 ++++++++++++++++--- scripts/powershell/common.ps1 | 67 +++++++++++++++++++---- scripts/powershell/create-new-feature.ps1 | 50 +++++++++++++++-- scripts/powershell/setup-plan.ps1 | 50 +++++++++++++++-- 5 files changed, 238 insertions(+), 34 deletions(-) diff --git a/scripts/bash/common.sh b/scripts/bash/common.sh index 582d940..92b00a8 100644 --- a/scripts/bash/common.sh +++ b/scripts/bash/common.sh @@ -1,16 +1,48 @@ #!/usr/bin/env bash -# (Moved to scripts/bash/) Common functions and variables for all scripts +# Common functions and variables for all scripts -get_repo_root() { git rev-parse --show-toplevel; } -get_current_branch() { git rev-parse --abbrev-ref HEAD; } +# Get repository root, with fallback for non-git repositories +get_repo_root() { + if git rev-parse --show-toplevel >/dev/null 2>&1; then + git rev-parse --show-toplevel + else + # Fall back to script location for non-git repos + local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + cd "$script_dir/../.." && pwd + fi +} + +# Get current branch, with fallback for non-git repositories +get_current_branch() { + if git rev-parse --abbrev-ref HEAD >/dev/null 2>&1; then + git rev-parse --abbrev-ref HEAD + else + echo "main" # Default branch name for non-git repos + fi +} + +# Check if we have git available +has_git() { + git rev-parse --show-toplevel >/dev/null 2>&1 +} check_feature_branch() { local branch="$1" + local has_git_repo="$2" + + # For non-git repos, we can't enforce branch naming but still provide output + if [[ "$has_git_repo" != "true" ]]; then + echo "[specify] Warning: Git repository not detected; skipped branch validation" >&2 + return 0 + fi + if [[ ! "$branch" =~ ^[0-9]{3}- ]]; then echo "ERROR: Not on a feature branch. Current branch: $branch" >&2 echo "Feature branches should be named like: 001-feature-name" >&2 return 1 - fi; return 0 + fi + + return 0 } get_feature_dir() { echo "$1/specs/$2"; } @@ -18,10 +50,18 @@ get_feature_dir() { echo "$1/specs/$2"; } get_feature_paths() { local repo_root=$(get_repo_root) local current_branch=$(get_current_branch) + local has_git_repo="false" + + if has_git; then + has_git_repo="true" + fi + local feature_dir=$(get_feature_dir "$repo_root" "$current_branch") + cat <$null + if ($LASTEXITCODE -eq 0) { + return $result + } + } catch { + # Git command failed + } + + # Fall back to script location for non-git repos + $scriptDir = Split-Path -Parent $PSScriptRoot + return (Resolve-Path (Join-Path $scriptDir "..")).Path } function Get-CurrentBranch { - git rev-parse --abbrev-ref HEAD + try { + $result = git rev-parse --abbrev-ref HEAD 2>$null + if ($LASTEXITCODE -eq 0) { + return $result + } + } catch { + # Git command failed + } + + # Default branch name for non-git repos + return "main" +} + +function Test-HasGit { + try { + git rev-parse --show-toplevel 2>$null | Out-Null + return ($LASTEXITCODE -eq 0) + } catch { + return $false + } } function Test-FeatureBranch { - param([string]$Branch) + param( + [string]$Branch, + [bool]$HasGit = $true + ) + + # For non-git repos, we can't enforce branch naming but still provide output + if (-not $HasGit) { + Write-Warning "[specify] Warning: Git repository not detected; skipped branch validation" + return $true + } + if ($Branch -notmatch '^[0-9]{3}-') { Write-Output "ERROR: Not on a feature branch. Current branch: $Branch" Write-Output "Feature branches should be named like: 001-feature-name" @@ -27,17 +67,20 @@ function Get-FeatureDir { function Get-FeaturePathsEnv { $repoRoot = Get-RepoRoot $currentBranch = Get-CurrentBranch + $hasGit = Test-HasGit $featureDir = Get-FeatureDir -RepoRoot $repoRoot -Branch $currentBranch + [PSCustomObject]@{ - REPO_ROOT = $repoRoot + REPO_ROOT = $repoRoot CURRENT_BRANCH = $currentBranch - FEATURE_DIR = $featureDir - FEATURE_SPEC = Join-Path $featureDir 'spec.md' - IMPL_PLAN = Join-Path $featureDir 'plan.md' - TASKS = Join-Path $featureDir 'tasks.md' - RESEARCH = Join-Path $featureDir 'research.md' - DATA_MODEL = Join-Path $featureDir 'data-model.md' - QUICKSTART = Join-Path $featureDir 'quickstart.md' + HAS_GIT = $hasGit + FEATURE_DIR = $featureDir + FEATURE_SPEC = Join-Path $featureDir 'spec.md' + IMPL_PLAN = Join-Path $featureDir 'plan.md' + TASKS = Join-Path $featureDir 'tasks.md' + RESEARCH = Join-Path $featureDir 'research.md' + DATA_MODEL = Join-Path $featureDir 'data-model.md' + QUICKSTART = Join-Path $featureDir 'quickstart.md' CONTRACTS_DIR = Join-Path $featureDir 'contracts' } } diff --git a/scripts/powershell/create-new-feature.ps1 b/scripts/powershell/create-new-feature.ps1 index b99f088..7e1a98c 100644 --- a/scripts/powershell/create-new-feature.ps1 +++ b/scripts/powershell/create-new-feature.ps1 @@ -1,5 +1,5 @@ #!/usr/bin/env pwsh -# Create a new feature (moved to powershell/) +# Create a new feature [CmdletBinding()] param( [switch]$Json, @@ -9,11 +9,31 @@ param( $ErrorActionPreference = 'Stop' if (-not $FeatureDescription -or $FeatureDescription.Count -eq 0) { - Write-Error "Usage: ./create-new-feature.ps1 [-Json] "; exit 1 + Write-Error "Usage: ./create-new-feature.ps1 [-Json] " + exit 1 } $featureDesc = ($FeatureDescription -join ' ').Trim() -$repoRoot = git rev-parse --show-toplevel +# Resolve repository root. Prefer git information when available, but fall back +# to the script location so the workflow still functions in repositories that +# were initialised with --no-git. +$scriptDir = Split-Path -Parent $PSScriptRoot +$fallbackRoot = (Resolve-Path (Join-Path $scriptDir "..")).Path + +try { + $repoRoot = git rev-parse --show-toplevel 2>$null + if ($LASTEXITCODE -eq 0) { + $hasGit = $true + } else { + throw "Git not available" + } +} catch { + $repoRoot = $fallbackRoot + $hasGit = $false +} + +Set-Location $repoRoot + $specsDir = Join-Path $repoRoot 'specs' New-Item -ItemType Directory -Path $specsDir -Force | Out-Null @@ -33,20 +53,38 @@ $branchName = $featureDesc.ToLower() -replace '[^a-z0-9]', '-' -replace '-{2,}', $words = ($branchName -split '-') | Where-Object { $_ } | Select-Object -First 3 $branchName = "$featureNum-$([string]::Join('-', $words))" -git checkout -b $branchName | Out-Null +if ($hasGit) { + try { + git checkout -b $branchName | Out-Null + } catch { + Write-Warning "Failed to create git branch: $branchName" + } +} else { + Write-Warning "[specify] Warning: Git repository not detected; skipped branch creation for $branchName" +} $featureDir = Join-Path $specsDir $branchName New-Item -ItemType Directory -Path $featureDir -Force | Out-Null $template = Join-Path $repoRoot 'templates/spec-template.md' $specFile = Join-Path $featureDir 'spec.md' -if (Test-Path $template) { Copy-Item $template $specFile -Force } else { New-Item -ItemType File -Path $specFile | Out-Null } +if (Test-Path $template) { + Copy-Item $template $specFile -Force +} else { + New-Item -ItemType File -Path $specFile | Out-Null +} if ($Json) { - $obj = [PSCustomObject]@{ BRANCH_NAME = $branchName; SPEC_FILE = $specFile; FEATURE_NUM = $featureNum } + $obj = [PSCustomObject]@{ + BRANCH_NAME = $branchName + SPEC_FILE = $specFile + FEATURE_NUM = $featureNum + HAS_GIT = $hasGit + } $obj | ConvertTo-Json -Compress } else { Write-Output "BRANCH_NAME: $branchName" Write-Output "SPEC_FILE: $specFile" Write-Output "FEATURE_NUM: $featureNum" + Write-Output "HAS_GIT: $hasGit" } diff --git a/scripts/powershell/setup-plan.ps1 b/scripts/powershell/setup-plan.ps1 index b026440..d0ed582 100644 --- a/scripts/powershell/setup-plan.ps1 +++ b/scripts/powershell/setup-plan.ps1 @@ -1,21 +1,61 @@ #!/usr/bin/env pwsh +# Setup implementation plan for a feature + [CmdletBinding()] -param([switch]$Json) +param( + [switch]$Json, + [switch]$Help +) + $ErrorActionPreference = 'Stop' + +# Show help if requested +if ($Help) { + Write-Output "Usage: ./setup-plan.ps1 [-Json] [-Help]" + Write-Output " -Json Output results in JSON format" + Write-Output " -Help Show this help message" + exit 0 +} + +# Load common functions . "$PSScriptRoot/common.ps1" +# Get all paths and variables from common functions $paths = Get-FeaturePathsEnv -if (-not (Test-FeatureBranch -Branch $paths.CURRENT_BRANCH)) { exit 1 } +# Check if we're on a proper feature branch (only for git repos) +if (-not (Test-FeatureBranch -Branch $paths.CURRENT_BRANCH -HasGit $paths.HAS_GIT)) { + exit 1 +} + +# Ensure the feature directory exists New-Item -ItemType Directory -Path $paths.FEATURE_DIR -Force | Out-Null -$template = Join-Path $paths.REPO_ROOT 'templates/plan-template.md' -if (Test-Path $template) { Copy-Item $template $paths.IMPL_PLAN -Force } +# Copy plan template if it exists, otherwise note it or create empty file +$template = Join-Path $paths.REPO_ROOT '.specify/templates/plan-template.md' +if (Test-Path $template) { + Copy-Item $template $paths.IMPL_PLAN -Force + Write-Output "Copied plan template to $($paths.IMPL_PLAN)" +} else { + Write-Warning "Plan template not found at $template" + # Create a basic plan file if template doesn't exist + New-Item -ItemType File -Path $paths.IMPL_PLAN -Force | Out-Null +} + +# Output results if ($Json) { - [PSCustomObject]@{ FEATURE_SPEC=$paths.FEATURE_SPEC; IMPL_PLAN=$paths.IMPL_PLAN; SPECS_DIR=$paths.FEATURE_DIR; BRANCH=$paths.CURRENT_BRANCH } | ConvertTo-Json -Compress + $result = [PSCustomObject]@{ + FEATURE_SPEC = $paths.FEATURE_SPEC + IMPL_PLAN = $paths.IMPL_PLAN + SPECS_DIR = $paths.FEATURE_DIR + BRANCH = $paths.CURRENT_BRANCH + HAS_GIT = $paths.HAS_GIT + } + $result | ConvertTo-Json -Compress } else { Write-Output "FEATURE_SPEC: $($paths.FEATURE_SPEC)" Write-Output "IMPL_PLAN: $($paths.IMPL_PLAN)" Write-Output "SPECS_DIR: $($paths.FEATURE_DIR)" Write-Output "BRANCH: $($paths.CURRENT_BRANCH)" + Write-Output "HAS_GIT: $($paths.HAS_GIT)" }