188 lines
5.9 KiB
PowerShell
188 lines
5.9 KiB
PowerShell
#Requires -Version 5.1
|
|
|
|
param(
|
|
[switch]$Yes
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$RootDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$EnvFile = Join-Path $RootDir ".env"
|
|
|
|
function Confirm-Run {
|
|
param(
|
|
[string]$Label,
|
|
[string]$ScriptPath
|
|
)
|
|
|
|
if ($Yes) {
|
|
Write-Host "[x] $Label not done yet. Running $ScriptPath (-Yes enabled)..."
|
|
& $ScriptPath
|
|
return
|
|
}
|
|
|
|
$answer = Read-Host "[x] $Label not done yet. Run now? [y/N]"
|
|
if ($answer -match '^[Yy]$') {
|
|
& $ScriptPath
|
|
}
|
|
}
|
|
|
|
function Get-EnvConfig {
|
|
if (-not (Test-Path $EnvFile)) {
|
|
throw "GCR/.env not found. Copy GCR/.env.example to GCR/.env first."
|
|
}
|
|
|
|
$cfg = @{}
|
|
foreach ($line in Get-Content $EnvFile) {
|
|
if ($line -match '^\s*$' -or $line -match '^\s*#') { continue }
|
|
if ($line -match '^([^=]+)=(.*)$') {
|
|
$cfg[$Matches[1].Trim()] = $Matches[2].Trim()
|
|
}
|
|
}
|
|
|
|
foreach ($key in @('GCP_PROJECT_ID', 'GCP_REGION', 'GCP_REPOSITORY', 'SERVICE_NAME')) {
|
|
if (-not $cfg[$key]) {
|
|
throw "$key is not set in GCR/.env"
|
|
}
|
|
}
|
|
|
|
return $cfg
|
|
}
|
|
|
|
function Test-GcloudInstalled {
|
|
return [bool](Get-Command gcloud -ErrorAction SilentlyContinue)
|
|
}
|
|
|
|
function Test-Login {
|
|
param([hashtable]$Cfg)
|
|
|
|
$activeAccount = (gcloud auth list --filter=status:ACTIVE --format="value(account)" 2>$null | Select-Object -First 1)
|
|
$currentProject = (gcloud config get-value project 2>$null)
|
|
$currentRegion = (gcloud config get-value run/region 2>$null)
|
|
|
|
$dockerCfg = if ($env:DOCKER_CONFIG) { Join-Path $env:DOCKER_CONFIG "config.json" } else { Join-Path $HOME ".docker\config.json" }
|
|
$dockerOk = $false
|
|
if (Test-Path $dockerCfg) {
|
|
$dockerPattern = "`"$($Cfg['GCP_REGION'])-docker.pkg.dev`""
|
|
$dockerOk = (Select-String -Path $dockerCfg -Pattern $dockerPattern -SimpleMatch -Quiet)
|
|
}
|
|
|
|
return (-not [string]::IsNullOrWhiteSpace($activeAccount)) -and
|
|
($currentProject.Trim() -eq $Cfg['GCP_PROJECT_ID']) -and
|
|
($currentRegion.Trim() -eq $Cfg['GCP_REGION']) -and
|
|
$dockerOk
|
|
}
|
|
|
|
function Test-ProjectSetup {
|
|
param([hashtable]$Cfg)
|
|
|
|
$billingEnabled = (gcloud billing projects describe $Cfg['GCP_PROJECT_ID'] --format='value(billingEnabled)' 2>$null)
|
|
if ($billingEnabled -ne 'True') { return $false }
|
|
|
|
try {
|
|
gcloud artifacts repositories describe $Cfg['GCP_REPOSITORY'] --location=$Cfg['GCP_REGION'] --project=$Cfg['GCP_PROJECT_ID'] 2>$null | Out-Null
|
|
} catch {
|
|
return $false
|
|
}
|
|
|
|
foreach ($api in @('run.googleapis.com', 'artifactregistry.googleapis.com', 'secretmanager.googleapis.com', 'cloudresourcemanager.googleapis.com')) {
|
|
$enabled = gcloud services list --enabled --project=$Cfg['GCP_PROJECT_ID'] --format='value(config.name)' 2>$null | Select-String -Pattern "^$([regex]::Escape($api))$"
|
|
if (-not $enabled) { return $false }
|
|
}
|
|
|
|
return $true
|
|
}
|
|
|
|
function Test-SecretsSetup {
|
|
param([hashtable]$Cfg)
|
|
|
|
try {
|
|
gcloud secrets describe mongodb-connection-string --project=$Cfg['GCP_PROJECT_ID'] 2>$null | Out-Null
|
|
} catch {
|
|
return $false
|
|
}
|
|
|
|
# Check if any service account has secretAccessor access (not just @appspot)
|
|
$bindings = gcloud secrets get-iam-policy mongodb-connection-string `
|
|
--project=$Cfg['GCP_PROJECT_ID'] `
|
|
--flatten='bindings[].members' `
|
|
--filter='bindings.role=roles/secretmanager.secretAccessor' `
|
|
--format='value(bindings.members)' 2>$null
|
|
|
|
return (-not [string]::IsNullOrWhiteSpace($bindings))
|
|
}
|
|
|
|
function Test-DeployDone {
|
|
param([hashtable]$Cfg)
|
|
|
|
try {
|
|
gcloud run services describe $Cfg['SERVICE_NAME'] --region=$Cfg['GCP_REGION'] --project=$Cfg['GCP_PROJECT_ID'] 2>$null | Out-Null
|
|
return $true
|
|
} catch {
|
|
return $false
|
|
}
|
|
}
|
|
|
|
function Write-Done {
|
|
param([string]$Text)
|
|
Write-Host "[v] $Text"
|
|
}
|
|
|
|
Write-Host "================================================================"
|
|
Write-Host " Htmx deployment flow runner (Windows)"
|
|
Write-Host "================================================================"
|
|
|
|
if (-not (Test-Path $EnvFile)) {
|
|
Write-Host "[x] Step 0: GCR/.env is missing"
|
|
Write-Host " Copy GCR/.env.example to GCR/.env and fill required values."
|
|
exit 1
|
|
}
|
|
|
|
Write-Done "Step 0: .env exists"
|
|
$cfg = Get-EnvConfig
|
|
|
|
if (Test-GcloudInstalled) {
|
|
Write-Done "Step 1: gcloud installed"
|
|
} else {
|
|
Confirm-Run "Step 1: gcloud install" (Join-Path $RootDir "scripts\00-install-gcloud.ps1")
|
|
}
|
|
|
|
if (Test-Login $cfg) {
|
|
Write-Done "Step 2: login + docker auth configured"
|
|
} else {
|
|
Confirm-Run "Step 2: login" (Join-Path $RootDir "scripts\01-login.ps1")
|
|
}
|
|
|
|
if (Test-ProjectSetup $cfg) {
|
|
Write-Done "Step 3: project setup complete"
|
|
} else {
|
|
Confirm-Run "Step 3: project setup" (Join-Path $RootDir "scripts\02-setup-project.ps1")
|
|
}
|
|
|
|
if (Test-SecretsSetup $cfg) {
|
|
Write-Done "Step 4: secrets created and access granted"
|
|
} else {
|
|
Confirm-Run "Step 4: secrets setup" (Join-Path $RootDir "scripts\03-create-secrets.ps1")
|
|
}
|
|
|
|
if (Test-DeployDone $cfg) {
|
|
Write-Done "Step 5: service is already deployed"
|
|
} else {
|
|
Confirm-Run "Step 5: deploy" (Join-Path $RootDir "scripts\04-deploy.ps1")
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "================================================================"
|
|
Write-Host " Final verification"
|
|
Write-Host "================================================================"
|
|
|
|
if (Test-GcloudInstalled) { Write-Done "Step 1" } else { Write-Host "[x] Step 1" }
|
|
if (Test-Login $cfg) { Write-Done "Step 2" } else { Write-Host "[x] Step 2" }
|
|
if (Test-ProjectSetup $cfg) { Write-Done "Step 3" } else { Write-Host "[x] Step 3" }
|
|
if (Test-SecretsSetup $cfg) { Write-Done "Step 4" } else { Write-Host "[x] Step 4" }
|
|
if (Test-DeployDone $cfg) { Write-Done "Step 5" } else { Write-Host "[x] Step 5" }
|
|
|
|
Write-Host ""
|
|
Write-Host "Tip: run .\GCR\run-all.ps1 -Yes to auto-run missing steps without prompts."
|