conv-commit.ps1
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# Commit Helper ================================================================

# Helpers ----------------------------------------------------------------------

function Write-Log {
    param(
        [Parameter(Mandatory = $true)][string] $Message,
        [ValidateSet("INF", "WRN", "ERR")][string] $Level = "INF"
    )
    $colors = @{ INF = "Blue"; WRN = "Yellow"; ERR = "Red" }
    Write-Host $Level -ForegroundColor $colors[$Level] -NoNewline
    Write-Host " $Message"
}

function Write-Menu {
    param([array]$Items)
    for ($I = 0; $I -lt $Items.Count; $I++) {
        Write-Host "  [$($I + 1)] " -ForegroundColor DarkGray -NoNewline
        Write-Host "$($Items[$I].Value)" -ForegroundColor Blue -NoNewline
        Write-Host " - $($Items[$I].Desc)" -ForegroundColor Gray
    }
}

function Read-Selection {
    param([array]$Items)
    while ($true) {
        $InputNum = Read-Host "`nEnter number"
        if ($InputNum -match '^\d+$') {
            $Index = [int]$InputNum - 1
            if ($Index -ge 0 -and $Index -lt $Items.Count) {
                return $Items[$Index]
            }
        }
        Write-Log "Invalid selection, try again." -Level WRN
    }
}

# Definitions ------------------------------------------------------------------

$Types = @(
    @{ Value = "feat"; Desc = "new feature or capability" }
    @{ Value = "fix"; Desc = "bug fix or correction" }
    @{ Value = "chore"; Desc = "maintenance, tooling, dependencies" }
    @{ Value = "docs"; Desc = "documentation changes" }
    @{ Value = "refactor"; Desc = "restructuring without behaviour change" }
    @{ Value = "revert"; Desc = "reverting a previous commit" }
)

$Scopes = @(
    @{ Value = "repo"; Desc = "repo-level housekeeping" }
    @{ Value = "hooks"; Desc = "git hooks" }
    @{ Value = "scripts"; Desc = "utility scripts" }
    @{ Value = "policies"; Desc = "OPA policy definitions" }
    @{ Value = "pipeline"; Desc = "pipeline scripts and config" }
)

# Execution entry point --------------------------------------------------------

Write-Host "`nConventional Commits Helper for IaC Policies Repository"

# Step 1: Ensure within a git repo & staged changes ----------------------------

git rev-parse --is-inside-work-tree 2>&1 | Out-Null
if ($LASTEXITCODE -ne 0) {
    Write-Host ""
    Write-Log "Does not appear to be a git repository." -Level ERR
    Write-Log "Please run this script from within the iac-policies repository." -Level WRN
    exit 1
}

$Staged = git diff --cached --name-only
if (-not $Staged) {
    Write-Host ""
    Write-Log "No staged files found. Run 'git add' before committing." -Level ERR
    exit 1
}

Push-Location
$RepoRoot = git rev-parse --show-toplevel
Set-Location $RepoRoot

# Step 2: Type -----------------------------------------------------------------

Write-Host "`nSelect commit type:" -ForegroundColor White
Write-Menu -Items $Types
$Type = (Read-Selection -Items $Types).Value

# Step 3: Scope ----------------------------------------------------------------

Write-Host "`nSelect scope:" -ForegroundColor White
Write-Menu -Items $Scopes
$Scope = (Read-Selection -Items $Scopes).Value

# Step 4: Description ----------------------------------------------------------

$Description = Read-Host "`nEnter commit description"

if ([string]::IsNullOrWhiteSpace($Description)) {
    Write-Log "Description cannot be empty." -Level ERR
    Pop-Location
    exit 1
}

if ($Description.Length -gt 72) {
    Write-Log "Description too long ($($Description.Length) chars). Keep it under 72." -Level ERR
    Pop-Location
    exit 1
}

# Step 5: Confirm --------------------------------------------------------------

$CommitMsg = "${Type}(${Scope}): ${Description}"
Write-Host "`nCommit Message: "
Write-Host "  $CommitMsg" -ForegroundColor Green
Write-Host ""

$Confirm = Read-Host "Confirm and commit changes? (y/n)"
if ($Confirm.ToLower() -ne "y") {
    Write-Host ""
    Write-Log "Commit aborted by user" -Level WRN
    Pop-Location
    exit 0
}

# Step 6: Commit ---------------------------------------------------------------

git commit -m $CommitMsg
$ExitCode = $LASTEXITCODE

# Step 7: Restore working directory --------------------------------------------

Pop-Location
exit $ExitCode