Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions app/Console/Commands/BulkDeployStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

namespace App\Console\Commands;

use App\Services\LagoonClientService;
use Illuminate\Console\Command;

class BulkDeployStatus extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'polydock:bulk-deploy:status {bulk_id : The bulk deployment ID}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Check status of a bulk deployment';

/**
* Execute the console command.
*/
public function handle()
{
$bulkId = $this->argument('bulk_id');

$this->info("Fetching status for bulk deployment ID: {$bulkId}...");

try {
$client = app(LagoonClientService::class)->getAuthenticatedClient();
$deployments = $client->getDeploymentsByBulkId($bulkId);

if (isset($deployments['error'])) {
$errors = is_array($deployments['error']) ? json_encode($deployments['error']) : $deployments['error'];
$this->error("Failed to fetch bulk deployment status: {$errors}");
return 1;
}

if (empty($deployments)) {
$this->warn("No deployments found for bulk ID: {$bulkId}");
return 0;
}

$total = count($deployments);
$stats = [
'new' => 0,
'pending' => 0,
'running' => 0,
'complete' => 0,
'failed' => 0,
'cancelled' => 0,
];

$rows = [];
foreach ($deployments as $deploy) {
$status = $deploy['status'] ?? 'unknown';
$stats[$status] = ($stats[$status] ?? 0) + 1;

$projectName = $deploy['environment']['project']['name'] ?? 'unknown';
$envName = $deploy['environment']['name'] ?? 'unknown';

$rows[] = [
$deploy['id'] ?? 'unknown',
$projectName,
$envName,
$status,
$deploy['started'] ?? '',
$deploy['completed'] ?? '',
];
}

$this->info("\nBulk Deployment Summary:");
$this->info("Total: {$total}");
foreach ($stats as $status => $count) {
if ($count > 0) {
$color = $this->getStatusColor($status);
$this->line("<fg={$color}>{$status}: {$count}</>");
}
}

$this->newLine();
$this->table(
['ID', 'Project', 'Environment', 'Status', 'Started', 'Completed'],
$rows
);

return 0;
} catch (\Exception $e) {
$this->error("Error checking bulk deployment status: {$e->getMessage()}");
return 1;
}
}

private function getStatusColor(string $status): string
{
return match ($status) {
'complete' => 'green',
'failed' => 'red',
'running' => 'blue',
'pending' => 'yellow',
'cancelled' => 'gray',
default => 'white',
};
}
}
121 changes: 51 additions & 70 deletions app/Console/Commands/TriggerLagoonDeployOnAppInstances.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,91 +155,72 @@ public function handle()
$this->table(headers: $headers, rows: $rows);
}

if ($concurrency > 1) {
$this->info(string: "Running deployments concurrently on {$count} instances (concurrency: {$concurrency})...");

$phpBinary = PHP_BINARY;
$artisan = base_path('artisan');
$commandBase = [
$phpBinary,
$artisan,
'polydock:app-instance:trigger-deploy',
$appUuid,
'--force',
];
if ($concurrency > 1 && ! $this->option('force')) {
$this->warn('Note: Concurrency option is ignored when using bulk deployment, as Lagoon handles parallelization natively.');
}

if ($envOverride) {
$commandBase[] = "--environment={$envOverride}";
}
if ($variablesOnly) {
$commandBase[] = '--variables-only';
}
$this->info(string: 'Authenticating with Lagoon...');
try {
$client = app(LagoonClientService::class)->getAuthenticatedClient();
} catch (\Exception $e) {
$this->error(string: "Authentication failed: {$e->getMessage()}");

$pool = Process::pool(function (Pool $pool) use ($instances, $commandBase) {
foreach ($instances as $instance) {
$command = array_merge($commandBase, ["--instance-id={$instance->id}"]);
$pool->as($instance->id)->command($command);
}
});
return 1;
}

try {
$pool->concurrency($concurrency);
} catch (\Throwable) {
// Ignore if method doesn't exist
$environments = [];
foreach ($instances as $instance) {
$projectName = $instance->getKeyValue('lagoon-project-name');
$branch = $envOverride ?: $instance->getKeyValue('lagoon-deploy-branch');

if ($projectName && $branch) {
$environments[] = [
'project' => $projectName,
'name' => $branch,
];
}
}

$poolResults = $pool->wait();
if (empty($environments)) {
$this->error('No valid environments found to deploy.');
return 1;
}

foreach ($poolResults as $instanceId => $result) {
$instance = $instances->find($instanceId);
if (! $instance) {
continue;
}
$buildVars = [];
if ($variablesOnly) {
$buildVars['LAGOON_VARIABLES_ONLY'] = 'true';
}

$projectName = $instance->getKeyValue(key: 'lagoon-project-name');
$bulkName = "Polydock Bulk Deploy: {$storeApp->name} (" . now()->toDateTimeString() . ")";

if ($result->successful()) {
// Output already contains "SUCCESS" or "FAILED" messages from child process
$this->output->write(messages: $result->output());
} else {
$this->error(string: "\n[FAILED] {$projectName} (Process Error): ".trim((string) $result->errorOutput()));
}
}
$this->info("Triggering bulk deployment for {$count} instances...");

try {
$result = $client->bulkDeployEnvironments(
environments: $environments,
name: $bulkName,
buildVariables: $buildVars
);

$this->info(string: 'Done.');
if (isset($result['error'])) {
$errors = is_array($result['error']) ? json_encode(value: $result['error']) : $result['error'];
$this->error(string: "Bulk deployment failed: {$errors}");

return 0;
}
return 1;
} else {
$bulkId = $result['bulkDeployEnvironmentLatest'] ?? 'unknown';
$this->info(string: "Bulk deployment triggered successfully! Bulk ID: {$bulkId}");

$this->info("\nYou can track the progress using:");
$this->info(" https://dashboard.amazeeio.cloud/deployments?bulkId={$bulkId}");

// Serial Logic
$this->info(string: 'Authenticating with Lagoon (Serial Mode)...');
try {
$client = app(LagoonClientService::class)->getAuthenticatedClient();
return 0;
}
} catch (\Exception $e) {
$this->error(string: "Authentication failed: {$e->getMessage()}");
$this->error(string: "Bulk deployment failed: {$e->getMessage()}");

return 1;
}

$bar = $this->output->createProgressBar(max: $count);
$bar->start();

/** @var PolydockAppInstance $instance */
foreach ($instances as $instance) {
$this->deployToInstance(
instance: $instance,
client: $client,
envOverride: $envOverride,
variablesOnly: $variablesOnly
);
$bar->advance();
}

$bar->finish();
$this->newLine();
$this->info(string: 'Done.');

return 0;
}

protected function deployToInstance(
Expand Down
9 changes: 5 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@
"php": "^8.3",
"ext-curl": "*",
"amazeeio/lagoon-logs": "^0.0.5",
"amazeeio/polydock-app-amazeeclaw": "^0.1.11",
"amazeeio/polydock-app-amazeeclaw": "^0.1",
"amazeeio/polydock-app-amazeeio-privategpt": "^0.1",
"amazeeio/polydock-app-anythingllm": "^0.1.2",
"dedoc/scramble": "^0.13.16",
"amazeeio/polydock-app-anythingllm": "^0.1",
"amazeeio/polydock-app-dependency-track": "^0.1.0",
"dedoc/scramble": "^0.13",
"evanschleret/lara-mjml": "^0.3.0",
"filament/filament": "^3.2",
"freedomtech-hosting/ft-lagoon-php": "^0.0.16",
"freedomtech-hosting/ft-lagoon-php": "^0.1",
"freedomtech-hosting/polydock-amazeeai-backend-client-php": "^0.1",
"freedomtech-hosting/polydock-app": "^0.0.33",
"freedomtech-hosting/polydock-app-amazeeio-generic": "^0.1",
Expand Down
Loading
Loading