Skip to content

Commit 3ea2df0

Browse files
committed
Create deploy command
1 parent f6458b2 commit 3ea2df0

File tree

4 files changed

+138
-0
lines changed

4 files changed

+138
-0
lines changed

config/nightwatch.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
'token' => env('NIGHTWATCH_TOKEN'),
66
'deployment' => env('NIGHTWATCH_DEPLOY'),
77
'server' => env('NIGHTWATCH_SERVER', (string) gethostname()),
8+
'base_url' => env('NIGHTWATCH_BASE_URL', 'https://nightwatch.laravel.com'),
89
'capture_exception_source_code' => env('NIGHTWATCH_CAPTURE_EXCEPTION_SOURCE_CODE', true),
910
'redact_headers' => explode(',', env('NIGHTWATCH_REDACT_HEADERS', 'Authorization,Cookie,Proxy-Authorization,X-XSRF-TOKEN')),
1011

src/Console/DeployCommand.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
namespace Laravel\Nightwatch\Console;
4+
5+
use Exception;
6+
use Illuminate\Console\Command;
7+
use Illuminate\Http\Client\Factory as HttpFactory;
8+
use SensitiveParameter;
9+
use Symfony\Component\Console\Attribute\AsCommand;
10+
11+
use function config;
12+
use function now;
13+
14+
/**
15+
* @internal
16+
*/
17+
#[AsCommand(name: 'nightwatch:deploy', description: 'Notice the Nightwatch agent that a new deployment has been made.')]
18+
final class DeployCommand extends Command
19+
{
20+
/**
21+
* @var string
22+
*/
23+
protected $signature = 'nightwatch:deploy';
24+
25+
protected $hidden = true;
26+
27+
/**
28+
* @var string
29+
*/
30+
protected $description = 'Notice the Nightwatch agent that a new deployment has been made.';
31+
32+
public function __construct(
33+
private HttpFactory $http,
34+
private ?string $baseUrl,
35+
#[SensitiveParameter] private ?string $token,
36+
) {
37+
parent::__construct();
38+
}
39+
40+
public function handle(): void
41+
{
42+
$tag = config('nightwatch.deployment') ?? '';
43+
44+
if (! $this->baseUrl) {
45+
$this->error('No Nightwatch base URL configured.');
46+
47+
return;
48+
}
49+
50+
if (! $this->token) {
51+
$this->error('No Nightwatch token configured.');
52+
53+
return;
54+
}
55+
56+
try {
57+
$response = $this->http
58+
->withHeaders([
59+
'Authorization' => "Bearer {$this->token}",
60+
'Accept' => 'application/json',
61+
'Content-Type' => 'application/json',
62+
])
63+
->post("{$this->baseUrl}/api/deployments", [
64+
'timestamp' => now()->timestamp,
65+
'version' => $tag,
66+
]);
67+
68+
if ($response->successful()) {
69+
$this->info('Deployment successful');
70+
} else {
71+
$this->error("Deployment failed: {$response->status()} {$response->body()}");
72+
}
73+
} catch (Exception $e) {
74+
$this->error("Deployment failed: {$e->getMessage()}");
75+
}
76+
}
77+
}

src/NightwatchServiceProvider.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
use Illuminate\Support\Facades\Context;
4141
use Illuminate\Support\ServiceProvider;
4242
use Laravel\Nightwatch\Console\AgentCommand;
43+
use Laravel\Nightwatch\Console\DeployCommand;
4344
use Laravel\Nightwatch\Facades\Nightwatch;
4445
use Laravel\Nightwatch\Factories\Logger;
4546
use Laravel\Nightwatch\Hooks\ArtisanStartingListener;
@@ -192,6 +193,7 @@ private function registerBindings(): void
192193
$this->registerLogger();
193194
$this->registerMiddleware();
194195
$this->registerAgentCommand();
196+
$this->registerDeployCommand();
195197
$this->buildAndRegisterCore();
196198
}
197199

@@ -226,6 +228,15 @@ private function registerAgentCommand(): void
226228
));
227229
}
228230

231+
private function registerDeployCommand(): void
232+
{
233+
$this->app->singleton(DeployCommand::class, fn () => new DeployCommand(
234+
http: $this->app->make(\Illuminate\Http\Client\Factory::class),
235+
token: $this->nightwatchConfig['token'] ?? null,
236+
baseUrl: $this->nightwatchConfig['base_url'] ?? null,
237+
));
238+
}
239+
229240
private function buildAndRegisterCore(): void
230241
{
231242
$clock = new Clock;
@@ -295,6 +306,7 @@ private function registerCommands(): void
295306
$this->commands([
296307
Console\AgentCommand::class,
297308
Console\StatusCommand::class,
309+
Console\DeployCommand::class,
298310
]);
299311
}
300312

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace Tests\Feature\Console;
4+
5+
use Illuminate\Process\Exceptions\ProcessTimedOutException;
6+
use Illuminate\Support\Facades\Process;
7+
use RuntimeException;
8+
use Tests\TestCase;
9+
10+
use function sleep;
11+
12+
class DeployCommandTest extends TestCase
13+
{
14+
public function test_it_can_run_the_agent_command(): void
15+
{
16+
$output = '';
17+
$process = Process::timeout(10)->start('NIGHTWATCH_TOKEN="test-token" \
18+
NIGHTWATCH_BASE_URL="http://localhost" \
19+
NIGHTWATCH_DEPLOY="v1.2.3" \
20+
vendor/bin/testbench nightwatch:deploy'
21+
);
22+
23+
try {
24+
$result = $process->wait(function ($type, $o) use (&$output, $process) {
25+
$output .= $o;
26+
27+
$process->signal(SIGTERM);
28+
29+
$tries = 0;
30+
31+
while ($tries < 3) {
32+
if (! $process->running()) {
33+
return;
34+
}
35+
36+
$tries++;
37+
sleep(1);
38+
}
39+
40+
$process->signal(SIGKILL);
41+
});
42+
} catch (ProcessTimedOutException $e) {
43+
throw new RuntimeException('Failed to deploy or stop the agent running. Output:'.PHP_EOL.$output, previous: $e);
44+
}
45+
46+
$this->assertStringContainsString('Deployment successful', $output);
47+
}
48+
}

0 commit comments

Comments
 (0)