@tamyla/clodo-framework 4.0.13 ā 4.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +7 -0
- package/dist/cli/commands/create.js +2 -1
- package/dist/middleware/Composer.js +38 -0
- package/dist/middleware/Registry.js +14 -0
- package/dist/middleware/index.js +3 -0
- package/dist/middleware/shared/basicAuth.js +21 -0
- package/dist/middleware/shared/cors.js +28 -0
- package/dist/middleware/shared/index.js +3 -0
- package/dist/middleware/shared/logging.js +14 -0
- package/dist/service-management/GenerationEngine.js +13 -2
- package/dist/service-management/ServiceOrchestrator.js +6 -2
- package/dist/service-management/generators/code/ServiceMiddlewareGenerator.js +156 -10
- package/dist/service-management/generators/code/WorkerIndexGenerator.js +75 -9
- package/dist/simple-api.js +32 -1
- package/docs/MIDDLEWARE_MIGRATION_SUMMARY.md +121 -0
- package/package.json +4 -1
- package/scripts/DEPLOY_COMMAND_NEW.js +128 -0
- package/scripts/README-automated-testing-suite.md +356 -0
- package/scripts/README-test-clodo-deployment.md +157 -0
- package/scripts/README.md +50 -0
- package/scripts/analyze-imports.ps1 +104 -0
- package/scripts/analyze-mixed-code.js +163 -0
- package/scripts/analyze-mixed-rationale.js +149 -0
- package/scripts/automated-testing-suite.js +776 -0
- package/scripts/deployment/README.md +31 -0
- package/scripts/deployment/deploy-domain.ps1 +449 -0
- package/scripts/deployment/deploy-staging.js +120 -0
- package/scripts/deployment/validate-staging.js +166 -0
- package/scripts/diagnose-imports.js +362 -0
- package/scripts/framework-diagnostic.js +368 -0
- package/scripts/migration/migrate-middleware-legacy-to-contract.js +47 -0
- package/scripts/post-publish-test.js +663 -0
- package/scripts/scan-worker-issues.js +52 -0
- package/scripts/service-management/README.md +27 -0
- package/scripts/service-management/setup-interactive.ps1 +693 -0
- package/scripts/test-clodo-deployment.js +588 -0
- package/scripts/test-downstream-install.js +237 -0
- package/scripts/test-local-package.ps1 +126 -0
- package/scripts/test-local-package.sh +166 -0
- package/scripts/test-package.js +339 -0
- package/scripts/testing/README.md +49 -0
- package/scripts/testing/test-first.ps1 +0 -0
- package/scripts/testing/test-first50.ps1 +0 -0
- package/scripts/testing/test.ps1 +0 -0
- package/scripts/utilities/README.md +61 -0
- package/scripts/utilities/check-bin.js +8 -0
- package/scripts/utilities/check-bundle.js +23 -0
- package/scripts/utilities/check-dist-imports.js +65 -0
- package/scripts/utilities/check-import-paths.js +191 -0
- package/scripts/utilities/cleanup-cli.js +159 -0
- package/scripts/utilities/deployment-helpers.ps1 +199 -0
- package/scripts/utilities/fix-dist-imports.js +135 -0
- package/scripts/utilities/generate-secrets.js +159 -0
- package/scripts/utilities/safe-push.ps1 +51 -0
- package/scripts/utilities/setup-helpers.ps1 +206 -0
- package/scripts/utilities/test-packaged-artifact.js +92 -0
- package/scripts/utilities/validate-dist-imports.js +189 -0
- package/scripts/utilities/validate-schema.js +102 -0
- package/scripts/verify-exports.js +193 -0
- package/scripts/verify-worker-safety.js +73 -0
- package/types/middleware.d.ts +1 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Deployment Scripts
|
|
2
|
+
|
|
3
|
+
Scripts for deploying Clodo Framework services to various environments and platforms.
|
|
4
|
+
|
|
5
|
+
## Scripts
|
|
6
|
+
|
|
7
|
+
### deploy-domain.ps1
|
|
8
|
+
Deploy services to specific domains with comprehensive validation and testing.
|
|
9
|
+
|
|
10
|
+
**Features:**
|
|
11
|
+
- Domain-specific deployment configuration
|
|
12
|
+
- Pre-deployment validation
|
|
13
|
+
- Automated testing (optional)
|
|
14
|
+
- Environment-specific settings
|
|
15
|
+
- Rollback capabilities
|
|
16
|
+
|
|
17
|
+
**Usage:**
|
|
18
|
+
```powershell
|
|
19
|
+
.\scripts\deployment\deploy-domain.ps1 -DomainName api.example.com -ServiceName my-api -Environment production
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Parameters:**
|
|
23
|
+
- `DomainName` - Target domain for deployment (required)
|
|
24
|
+
- `ServiceName` - Name of the service to deploy
|
|
25
|
+
- `Environment` - Target environment (development, staging, production)
|
|
26
|
+
- `SkipTests` - Skip automated testing
|
|
27
|
+
- `SkipValidation` - Skip pre-deployment validation
|
|
28
|
+
- `DryRun` - Show what would be deployed without actually deploying
|
|
29
|
+
- `ConfigPath` - Path to domain configuration file
|
|
30
|
+
- `WranglerPath` - Path to wrangler configuration file
|
|
31
|
+
- `PackagePath` - Path to package.json file
|
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[Parameter(Mandatory=$true)]
|
|
3
|
+
[string]$DomainName,
|
|
4
|
+
|
|
5
|
+
[Parameter(Mandatory=$false)]
|
|
6
|
+
[string]$ServiceName = "generic-service",
|
|
7
|
+
|
|
8
|
+
[Parameter(Mandatory=$false)]
|
|
9
|
+
[ValidateSet("development", "staging", "production")]
|
|
10
|
+
[string]$Environment = "staging",
|
|
11
|
+
|
|
12
|
+
[Parameter(Mandatory=$false)]
|
|
13
|
+
[switch]$SkipTests,
|
|
14
|
+
|
|
15
|
+
[Parameter(Mandatory=$false)]
|
|
16
|
+
[switch]$SkipValidation,
|
|
17
|
+
|
|
18
|
+
[Parameter(Mandatory=$false)]
|
|
19
|
+
[switch]$DryRun,
|
|
20
|
+
|
|
21
|
+
[Parameter(Mandatory=$false)]
|
|
22
|
+
[string]$ConfigPath = ".\src\config\domains.js",
|
|
23
|
+
|
|
24
|
+
[Parameter(Mandatory=$false)]
|
|
25
|
+
[string]$WranglerPath = ".\wrangler.toml",
|
|
26
|
+
|
|
27
|
+
[Parameter(Mandatory=$false)]
|
|
28
|
+
[string]$PackagePath = ".\package.json"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Import Clodo Framework utilities
|
|
32
|
+
. "$PSScriptRoot\..\utilities\deployment-helpers.ps1"
|
|
33
|
+
|
|
34
|
+
# Configuration
|
|
35
|
+
$ErrorActionPreference = "Stop"
|
|
36
|
+
$ProgressPreference = "SilentlyContinue"
|
|
37
|
+
|
|
38
|
+
# Colors for output
|
|
39
|
+
$Green = "Green"
|
|
40
|
+
$Yellow = "Yellow"
|
|
41
|
+
$Red = "Red"
|
|
42
|
+
$Cyan = "Cyan"
|
|
43
|
+
$White = "White"
|
|
44
|
+
|
|
45
|
+
function Write-Step {
|
|
46
|
+
param([string]$Message)
|
|
47
|
+
Write-Host "==> $Message" -ForegroundColor $Cyan
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function Write-Success {
|
|
51
|
+
param([string]$Message)
|
|
52
|
+
Write-Host "ā $Message" -ForegroundColor $Green
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function Write-Warning {
|
|
56
|
+
param([string]$Message)
|
|
57
|
+
Write-Host "ā $Message" -ForegroundColor $Yellow
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function Write-Error-Message {
|
|
61
|
+
param([string]$Message)
|
|
62
|
+
Write-Host "ā $Message" -ForegroundColor $Red
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function Exit-WithError {
|
|
66
|
+
param([string]$Message, [int]$ExitCode = 1)
|
|
67
|
+
Write-Error-Message $Message
|
|
68
|
+
exit $ExitCode
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# Main deployment function
|
|
72
|
+
function Invoke-ServiceDeployment {
|
|
73
|
+
Write-Step "Starting deployment of $ServiceName for domain $DomainName ($Environment)"
|
|
74
|
+
|
|
75
|
+
# Validate prerequisites
|
|
76
|
+
if (-not $SkipValidation) {
|
|
77
|
+
Test-Prerequisites
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# Load and validate domain configuration
|
|
81
|
+
$domainConfig = Get-DomainConfig -DomainName $DomainName -ConfigPath $ConfigPath
|
|
82
|
+
if (-not $domainConfig) {
|
|
83
|
+
Exit-WithError "Domain configuration not found for: $DomainName"
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
Write-Success "Domain configuration loaded: $($domainConfig.displayName)"
|
|
87
|
+
|
|
88
|
+
# Validate service configuration
|
|
89
|
+
if (-not $SkipValidation) {
|
|
90
|
+
Test-ServiceConfiguration -DomainConfig $domainConfig -ServiceName $ServiceName
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# Prepare deployment environment
|
|
94
|
+
$deployConfig = New-DeploymentConfig -DomainConfig $domainConfig -Environment $Environment -ServiceName $ServiceName
|
|
95
|
+
|
|
96
|
+
# Generate wrangler configuration
|
|
97
|
+
Write-Step "Generating wrangler configuration"
|
|
98
|
+
$wranglerConfig = New-WranglerConfig -DeployConfig $deployConfig -TemplatePath $WranglerPath
|
|
99
|
+
|
|
100
|
+
if ($DryRun) {
|
|
101
|
+
Write-Warning "DRY RUN: Would write wrangler config to $($wranglerConfig.Path)"
|
|
102
|
+
Write-Host ($wranglerConfig.Content | ConvertTo-Json -Depth 10) -ForegroundColor $White
|
|
103
|
+
} else {
|
|
104
|
+
$wranglerConfig.Content | Out-File -FilePath $wranglerConfig.Path -Encoding UTF8
|
|
105
|
+
Write-Success "Wrangler configuration generated"
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
# Install dependencies
|
|
109
|
+
if (-not $DryRun -and (Test-Path $PackagePath)) {
|
|
110
|
+
Write-Step "Installing dependencies"
|
|
111
|
+
Invoke-Command "npm install" -ErrorAction Stop
|
|
112
|
+
Write-Success "Dependencies installed"
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# Run tests
|
|
116
|
+
if (-not $SkipTests -and -not $DryRun) {
|
|
117
|
+
Write-Step "Running tests"
|
|
118
|
+
try {
|
|
119
|
+
Invoke-Command "npm test" -ErrorAction Stop
|
|
120
|
+
Write-Success "Tests passed"
|
|
121
|
+
} catch {
|
|
122
|
+
Write-Warning "Tests failed, but continuing with deployment"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# Create/update databases
|
|
127
|
+
if (-not $DryRun) {
|
|
128
|
+
Write-Step "Setting up databases"
|
|
129
|
+
Initialize-ServiceDatabases -DeployConfig $deployConfig
|
|
130
|
+
Write-Success "Databases configured"
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# Deploy to Cloudflare
|
|
134
|
+
if (-not $DryRun) {
|
|
135
|
+
Write-Step "Deploying to Cloudflare Workers"
|
|
136
|
+
$deployResult = Publish-CloudflareWorker -DeployConfig $deployConfig
|
|
137
|
+
|
|
138
|
+
if ($deployResult.Success) {
|
|
139
|
+
Write-Success "Deployment completed successfully"
|
|
140
|
+
Write-Host "Worker URL: $($deployResult.Url)" -ForegroundColor $Green
|
|
141
|
+
Write-Host "Deployment ID: $($deployResult.DeploymentId)" -ForegroundColor $White
|
|
142
|
+
} else {
|
|
143
|
+
Exit-WithError "Deployment failed: $($deployResult.Error)"
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
Write-Warning "DRY RUN: Would deploy to Cloudflare Workers"
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
# Run post-deployment validation
|
|
150
|
+
if (-not $DryRun -and -not $SkipValidation) {
|
|
151
|
+
Write-Step "Running post-deployment validation"
|
|
152
|
+
$validationResult = Test-DeploymentHealth -DeployConfig $deployConfig
|
|
153
|
+
|
|
154
|
+
if ($validationResult.Success) {
|
|
155
|
+
Write-Success "Post-deployment validation passed"
|
|
156
|
+
} else {
|
|
157
|
+
Write-Warning "Post-deployment validation failed: $($validationResult.Error)"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
Write-Step "Deployment process completed"
|
|
162
|
+
if ($DryRun) {
|
|
163
|
+
Write-Warning "This was a dry run - no actual deployment occurred"
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
# Validate prerequisites
|
|
168
|
+
function Test-Prerequisites {
|
|
169
|
+
Write-Step "Validating prerequisites"
|
|
170
|
+
|
|
171
|
+
# Check Node.js
|
|
172
|
+
try {
|
|
173
|
+
$nodeVersion = & node --version 2>$null
|
|
174
|
+
Write-Success "Node.js found: $nodeVersion"
|
|
175
|
+
} catch {
|
|
176
|
+
Exit-WithError "Node.js is not installed or not in PATH"
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
# Check npm
|
|
180
|
+
try {
|
|
181
|
+
$npmVersion = & npm --version 2>$null
|
|
182
|
+
Write-Success "npm found: v$npmVersion"
|
|
183
|
+
} catch {
|
|
184
|
+
Exit-WithError "npm is not installed or not in PATH"
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
# Check wrangler
|
|
188
|
+
try {
|
|
189
|
+
$wranglerVersion = & npx wrangler --version 2>$null
|
|
190
|
+
Write-Success "Wrangler found: $wranglerVersion"
|
|
191
|
+
} catch {
|
|
192
|
+
Exit-WithError "Wrangler is not installed. Run: npm install -g wrangler"
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
# Check PowerShell version
|
|
196
|
+
if ($PSVersionTable.PSVersion.Major -lt 5) {
|
|
197
|
+
Exit-WithError "PowerShell 5.0 or higher is required"
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
Write-Success "Prerequisites validation completed"
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
# Load domain configuration
|
|
204
|
+
function Get-DomainConfig {
|
|
205
|
+
param([string]$DomainName, [string]$ConfigPath)
|
|
206
|
+
|
|
207
|
+
if (-not (Test-Path $ConfigPath)) {
|
|
208
|
+
return $null
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
# This is a simplified version - in practice, you'd parse the JS config file
|
|
213
|
+
# For now, we'll assume the config is available as a PowerShell object
|
|
214
|
+
# In a real implementation, you might use Node.js to parse the JS file
|
|
215
|
+
|
|
216
|
+
Write-Warning "Note: Domain config parsing from JS files requires Node.js integration"
|
|
217
|
+
Write-Warning "For now, using mock configuration"
|
|
218
|
+
|
|
219
|
+
# Mock domain config - replace with actual parsing logic
|
|
220
|
+
return @{
|
|
221
|
+
name = $DomainName
|
|
222
|
+
displayName = "$DomainName Service"
|
|
223
|
+
accountId = "mock-account-id"
|
|
224
|
+
zoneId = "mock-zone-id"
|
|
225
|
+
domains = @{
|
|
226
|
+
production = "api.$DomainName.com"
|
|
227
|
+
staging = "staging-api.$DomainName.com"
|
|
228
|
+
development = "dev-api.$DomainName.com"
|
|
229
|
+
}
|
|
230
|
+
databases = @(
|
|
231
|
+
@{
|
|
232
|
+
name = "${DomainName}-db"
|
|
233
|
+
type = "d1"
|
|
234
|
+
}
|
|
235
|
+
)
|
|
236
|
+
features = @{
|
|
237
|
+
authentication = $true
|
|
238
|
+
logging = $true
|
|
239
|
+
monitoring = ($Environment -eq "production")
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
} catch {
|
|
243
|
+
Write-Error-Message "Failed to load domain configuration: $_"
|
|
244
|
+
return $null
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
# Validate service configuration
|
|
249
|
+
function Test-ServiceConfiguration {
|
|
250
|
+
param($DomainConfig, [string]$ServiceName)
|
|
251
|
+
|
|
252
|
+
# Check if service has required configuration
|
|
253
|
+
if (-not $DomainConfig.databases -and -not $DomainConfig.services) {
|
|
254
|
+
Write-Warning "No databases or services configured for $ServiceName"
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
# Validate environment-specific settings
|
|
258
|
+
if (-not $DomainConfig.domains.$Environment) {
|
|
259
|
+
Write-Warning "No domain configured for environment: $Environment"
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
Write-Success "Service configuration validated"
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
# Create deployment configuration
|
|
266
|
+
function New-DeploymentConfig {
|
|
267
|
+
param($DomainConfig, [string]$Environment, [string]$ServiceName)
|
|
268
|
+
|
|
269
|
+
return @{
|
|
270
|
+
domain = $DomainConfig
|
|
271
|
+
environment = $Environment
|
|
272
|
+
serviceName = $ServiceName
|
|
273
|
+
timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
|
274
|
+
deploymentId = [Guid]::NewGuid().ToString()
|
|
275
|
+
workerName = "$ServiceName-$Environment-$DomainName"
|
|
276
|
+
domainUrl = $DomainConfig.domains.$Environment
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
# Generate wrangler configuration
|
|
281
|
+
function New-WranglerConfig {
|
|
282
|
+
param($DeployConfig, [string]$TemplatePath)
|
|
283
|
+
|
|
284
|
+
$config = @"
|
|
285
|
+
name = "$($DeployConfig.workerName)"
|
|
286
|
+
main = "src/worker/index.js"
|
|
287
|
+
compatibility_date = "$(Get-Date -Format "yyyy-MM-dd")"
|
|
288
|
+
|
|
289
|
+
[env.$($DeployConfig.environment)]
|
|
290
|
+
"@
|
|
291
|
+
|
|
292
|
+
# Add database bindings
|
|
293
|
+
if ($DeployConfig.domain.databases) {
|
|
294
|
+
foreach ($db in $DeployConfig.domain.databases) {
|
|
295
|
+
$config += @"
|
|
296
|
+
|
|
297
|
+
[[d1_databases]]
|
|
298
|
+
binding = "$($db.name)"
|
|
299
|
+
database_name = "$($db.name)"
|
|
300
|
+
database_id = "$($db.id)"
|
|
301
|
+
"@
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
# Add environment variables
|
|
306
|
+
$config += @"
|
|
307
|
+
|
|
308
|
+
[vars]
|
|
309
|
+
DOMAIN_NAME = "$($DeployConfig.domain.name)"
|
|
310
|
+
ENVIRONMENT = "$($DeployConfig.environment)"
|
|
311
|
+
SERVICE_NAME = "$($DeployConfig.serviceName)"
|
|
312
|
+
DEPLOYMENT_ID = "$($DeployConfig.deploymentId)"
|
|
313
|
+
"@
|
|
314
|
+
|
|
315
|
+
# Add domain routing if configured
|
|
316
|
+
if ($DeployConfig.domainUrl) {
|
|
317
|
+
$config += @"
|
|
318
|
+
|
|
319
|
+
[[routes]]
|
|
320
|
+
pattern = "$($DeployConfig.domainUrl)/*"
|
|
321
|
+
zone_id = "$($DeployConfig.domain.zoneId)"
|
|
322
|
+
"@
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return @{
|
|
326
|
+
Path = $TemplatePath
|
|
327
|
+
Content = $config
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
# Initialize service databases
|
|
332
|
+
function Initialize-ServiceDatabases {
|
|
333
|
+
param($DeployConfig)
|
|
334
|
+
|
|
335
|
+
if (-not $DeployConfig.domain.databases) {
|
|
336
|
+
Write-Warning "No databases configured for service"
|
|
337
|
+
return
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
foreach ($db in $DeployConfig.domain.databases) {
|
|
341
|
+
Write-Step "Setting up database: $($db.name)"
|
|
342
|
+
|
|
343
|
+
try {
|
|
344
|
+
# Create database if it doesn't exist
|
|
345
|
+
$createResult = Invoke-Command "npx wrangler d1 create $($db.name)" -ErrorAction Stop
|
|
346
|
+
|
|
347
|
+
if ($createResult -match "database_id = (.+)") {
|
|
348
|
+
$db.id = $matches[1]
|
|
349
|
+
Write-Success "Database created: $($db.name)"
|
|
350
|
+
} else {
|
|
351
|
+
Write-Warning "Database may already exist: $($db.name)"
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
# Run migrations if they exist
|
|
355
|
+
$migrationPath = ".\migrations"
|
|
356
|
+
if (Test-Path $migrationPath) {
|
|
357
|
+
Write-Step "Running database migrations"
|
|
358
|
+
Invoke-Command "npx wrangler d1 migrations apply $($db.name) --local" -ErrorAction Stop
|
|
359
|
+
Write-Success "Migrations applied"
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
} catch {
|
|
363
|
+
Write-Error-Message "Failed to setup database $($db.name): $_"
|
|
364
|
+
# Continue with other databases
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
# Deploy to Cloudflare Workers
|
|
370
|
+
function Publish-CloudflareWorker {
|
|
371
|
+
param($DeployConfig)
|
|
372
|
+
|
|
373
|
+
try {
|
|
374
|
+
Write-Step "Publishing worker: $($DeployConfig.workerName)"
|
|
375
|
+
|
|
376
|
+
$deployCommand = "npx wrangler deploy --env $($DeployConfig.environment)"
|
|
377
|
+
$result = Invoke-Command $deployCommand -ErrorAction Stop
|
|
378
|
+
|
|
379
|
+
# Parse deployment result
|
|
380
|
+
$urlMatch = $result | Select-String -Pattern "https://(.+)\.workers\.dev"
|
|
381
|
+
$deploymentUrl = if ($urlMatch) { $urlMatch.Matches[0].Value } else { $null }
|
|
382
|
+
|
|
383
|
+
return @{
|
|
384
|
+
Success = $true
|
|
385
|
+
Url = $deploymentUrl
|
|
386
|
+
DeploymentId = $DeployConfig.deploymentId
|
|
387
|
+
Output = $result
|
|
388
|
+
}
|
|
389
|
+
} catch {
|
|
390
|
+
return @{
|
|
391
|
+
Success = $false
|
|
392
|
+
Error = $_.Exception.Message
|
|
393
|
+
Output = $result
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
# Test deployment health
|
|
399
|
+
function Test-DeploymentHealth {
|
|
400
|
+
param($DeployConfig)
|
|
401
|
+
|
|
402
|
+
if (-not $DeployConfig.domainUrl) {
|
|
403
|
+
return @{ Success = $true; Message = "No domain URL configured for health check" }
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
try {
|
|
407
|
+
Write-Step "Testing deployment health at: $($DeployConfig.domainUrl)"
|
|
408
|
+
|
|
409
|
+
# Simple health check - try to access the worker
|
|
410
|
+
$response = Invoke-WebRequest -Uri "$($DeployConfig.domainUrl)/health" -TimeoutSec 30 -ErrorAction Stop
|
|
411
|
+
|
|
412
|
+
if ($response.StatusCode -eq 200) {
|
|
413
|
+
Write-Success "Health check passed"
|
|
414
|
+
return @{ Success = $true }
|
|
415
|
+
} else {
|
|
416
|
+
return @{ Success = $false; Error = "Health check returned status $($response.StatusCode)" }
|
|
417
|
+
}
|
|
418
|
+
} catch {
|
|
419
|
+
return @{ Success = $false; Error = "Health check failed: $_" }
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
# Utility function to run commands
|
|
424
|
+
function Invoke-Command {
|
|
425
|
+
param([string]$Command, [switch]$ErrorAction)
|
|
426
|
+
|
|
427
|
+
Write-Host "Running: $Command" -ForegroundColor $White
|
|
428
|
+
|
|
429
|
+
try {
|
|
430
|
+
$output = Invoke-Expression $Command 2>&1
|
|
431
|
+
if ($LASTEXITCODE -ne 0 -and $ErrorAction) {
|
|
432
|
+
throw "Command failed with exit code $LASTEXITCODE"
|
|
433
|
+
}
|
|
434
|
+
return $output
|
|
435
|
+
} catch {
|
|
436
|
+
if ($ErrorAction) {
|
|
437
|
+
throw
|
|
438
|
+
}
|
|
439
|
+
Write-Error-Message "Command failed: $_"
|
|
440
|
+
return $null
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
# Run main deployment
|
|
445
|
+
try {
|
|
446
|
+
Invoke-ServiceDeployment
|
|
447
|
+
} catch {
|
|
448
|
+
Exit-WithError "Deployment failed: $_"
|
|
449
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Staging Deployment Script
|
|
5
|
+
*
|
|
6
|
+
* This script sets up staging environment variables and deploys to staging.
|
|
7
|
+
* Make sure to copy .env.staging.example to .env.staging and fill in your credentials.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { execSync } from 'child_process';
|
|
11
|
+
import { readFileSync, existsSync } from 'fs';
|
|
12
|
+
import { resolve } from 'path';
|
|
13
|
+
import chalk from 'chalk';
|
|
14
|
+
|
|
15
|
+
const ENV_FILE = '.env.staging';
|
|
16
|
+
const CONFIG_FILE = 'config/staging-deployment.json';
|
|
17
|
+
|
|
18
|
+
console.log(chalk.blue('š Starting Staging Deployment...\n'));
|
|
19
|
+
|
|
20
|
+
// Check if staging environment file exists
|
|
21
|
+
if (!existsSync(ENV_FILE)) {
|
|
22
|
+
console.error(chalk.red(`ā Error: ${ENV_FILE} not found!`));
|
|
23
|
+
console.log(chalk.yellow('Please copy .env.staging.example to .env.staging and fill in your credentials.'));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Load environment variables from staging file
|
|
28
|
+
try {
|
|
29
|
+
const envContent = readFileSync(ENV_FILE, 'utf8');
|
|
30
|
+
const envVars = {};
|
|
31
|
+
|
|
32
|
+
envContent.split('\n').forEach(line => {
|
|
33
|
+
const trimmed = line.trim();
|
|
34
|
+
if (trimmed && !trimmed.startsWith('#')) {
|
|
35
|
+
const [key, ...valueParts] = trimmed.split('=');
|
|
36
|
+
if (key && valueParts.length > 0) {
|
|
37
|
+
envVars[key] = valueParts.join('=');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Set environment variables
|
|
43
|
+
Object.entries(envVars).forEach(([key, value]) => {
|
|
44
|
+
process.env[key] = value;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
console.log(chalk.green('ā
Staging environment variables loaded'));
|
|
48
|
+
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error(chalk.red('ā Error loading staging environment variables:'), error.message);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Validate required environment variables
|
|
55
|
+
const requiredVars = ['CLOUDFLARE_API_TOKEN', 'CLOUDFLARE_ACCOUNT_ID', 'CLOUDFLARE_ZONE_ID'];
|
|
56
|
+
const missingVars = requiredVars.filter(varName => !process.env[varName]);
|
|
57
|
+
|
|
58
|
+
if (missingVars.length > 0) {
|
|
59
|
+
console.error(chalk.red('ā Missing required environment variables:'), missingVars.join(', '));
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log(chalk.green('ā
All required credentials present'));
|
|
64
|
+
|
|
65
|
+
// Check if config file exists
|
|
66
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
67
|
+
console.error(chalk.red(`ā Error: ${CONFIG_FILE} not found!`));
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(chalk.green('ā
Staging deployment configuration found'));
|
|
72
|
+
|
|
73
|
+
// Run deployment with dry-run first
|
|
74
|
+
console.log(chalk.yellow('\nš Running dry-run deployment first...'));
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const dryRunCommand = `npx clodo-service deploy --config-file ${CONFIG_FILE} --environment staging --dry-run --verbose`;
|
|
78
|
+
console.log(chalk.gray(`Executing: ${dryRunCommand}`));
|
|
79
|
+
|
|
80
|
+
execSync(dryRunCommand, {
|
|
81
|
+
stdio: 'inherit',
|
|
82
|
+
env: { ...process.env, FORCE_COLOR: '1' }
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
console.log(chalk.green('ā
Dry-run completed successfully'));
|
|
86
|
+
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error(chalk.red('ā Dry-run failed:'), error.message);
|
|
89
|
+
console.log(chalk.yellow('Please fix the issues above before proceeding with actual deployment.'));
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Ask for confirmation before actual deployment
|
|
94
|
+
console.log(chalk.yellow('\nā ļø Dry-run successful! Ready for actual deployment.'));
|
|
95
|
+
console.log(chalk.cyan('This will deploy to staging environment. Continue? (y/N): '));
|
|
96
|
+
|
|
97
|
+
// For automated deployment, we'll proceed automatically
|
|
98
|
+
console.log(chalk.blue('š Proceeding with staging deployment...\n'));
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
const deployCommand = `npx clodo-service deploy --config-file ${CONFIG_FILE} --environment staging --verbose`;
|
|
102
|
+
console.log(chalk.gray(`Executing: ${deployCommand}`));
|
|
103
|
+
|
|
104
|
+
execSync(deployCommand, {
|
|
105
|
+
stdio: 'inherit',
|
|
106
|
+
env: { ...process.env, FORCE_COLOR: '1' }
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
console.log(chalk.green('\nš Staging deployment completed successfully!'));
|
|
110
|
+
console.log(chalk.cyan('\nš Next steps:'));
|
|
111
|
+
console.log(chalk.white(' 1. Verify staging deployment at: https://staging.example.com'));
|
|
112
|
+
console.log(chalk.white(' 2. Check monitoring dashboard'));
|
|
113
|
+
console.log(chalk.white(' 3. Run integration tests against staging'));
|
|
114
|
+
console.log(chalk.white(' 4. If successful, proceed to production deployment'));
|
|
115
|
+
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error(chalk.red('\nā Staging deployment failed:'), error.message);
|
|
118
|
+
console.log(chalk.yellow('Check the error details above and try again.'));
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|