mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-06 13:10:37 -04:00
test: consolidate webhook repository URL tests and cover compose location save
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
3aa6ff1fdd
commit
35d4888c1a
@@ -17,6 +17,7 @@
|
||||
- Never run `php artisan test` inside a dev container (`./scripts/dev exec` or `docker exec coolify-dev-*`). The container sets `DB_CONNECTION=pgsql` as a real environment variable, which wins over `phpunit.xml`, so `RefreshDatabase` runs `migrate:fresh` on the dev database and wipes it. Run tests on the host only.
|
||||
- The helper image runs `docker compose` for deployments and for the Coolify upgrade itself. Before you bump its Docker CLI or Compose, test them against the oldest supported Docker Engine (for example a `docker:<version>-dind` container); newer clients can reject data from older daemons.
|
||||
- Do not symlink `vendor` into another worktree. Composer resolves the base path from the real `vendor` path, so the tests load the app classes of the other checkout. Run `composer install --ignore-platform-req=ext-zip` in the worktree.
|
||||
- To assert that the unsaved-changes bar shows, check `el.classList.contains('is-dirty')`. Playwright treats the hidden bar (`opacity-0`) as visible, and its class attribute always contains the text `is-dirty` from Tailwind variants.
|
||||
- Call `visit()` directly in each `tests/v4/Browser` test body; Pest does not mark a test that only uses helper-wrapped `visit()` as a browser test, so it fails with `sendText() on null`.
|
||||
|
||||
## Verify the complete user flow
|
||||
|
||||
@@ -917,139 +917,33 @@ describe('Manual Webhook Repository Matching', function () {
|
||||
],
|
||||
]);
|
||||
|
||||
test('github matches ssh git repository URL exactly', function () {
|
||||
$app = createApplicationWithWebhook(overrides: [
|
||||
'git_repository' => 'git@github.com:test-org/test-repo.git',
|
||||
]);
|
||||
$secret = $app->manual_webhook_secret_github;
|
||||
test('signed pushes deploy applications whose repository URL names the pushed repository', function (string $provider, string $gitRepository) {
|
||||
Queue::fake();
|
||||
$application = makeWebhookApplicationServerFunctional(createApplicationWithWebhook(overrides: [
|
||||
'git_repository' => $gitRepository,
|
||||
]));
|
||||
|
||||
$payload = json_encode([
|
||||
'ref' => 'refs/heads/main',
|
||||
'repository' => ['full_name' => 'test-org/test-repo'],
|
||||
'after' => 'abc1234',
|
||||
'commits' => [],
|
||||
]);
|
||||
sendManualWebhookPush($this, $provider, $application)->assertOk();
|
||||
|
||||
$response = $this->call('POST', '/webhooks/source/github/events/manual', [], [], [], [
|
||||
'HTTP_X-GitHub-Event' => 'push',
|
||||
'HTTP_X-Hub-Signature-256' => 'sha256='.hash_hmac('sha256', $payload, $secret),
|
||||
'CONTENT_TYPE' => 'application/json',
|
||||
], $payload);
|
||||
expect(ApplicationDeploymentQueue::query()->where('application_id', $application->id)->exists())->toBeTrue();
|
||||
})->with(['github', 'gitlab', 'bitbucket', 'gitea'])->with([
|
||||
'scp-style' => 'git@git.example.com:test-org/test-repo.git',
|
||||
'scp-style with custom port' => 'git@10.0.0.80:2222/test-org/test-repo.git',
|
||||
'scp-style with custom user and port' => 'custom-user@git.example.com:2222/test-org/test-repo.git',
|
||||
'ssh scheme with custom port' => 'ssh://git@10.0.0.80:2222/test-org/test-repo.git',
|
||||
'https with different case' => 'https://github.com/Test-Org/Test-Repo.git',
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
expect($response->getContent())->not->toContain('No applications found');
|
||||
});
|
||||
test('signed pushes do not deploy applications for another repository', function (string $provider) {
|
||||
Queue::fake();
|
||||
$application = makeWebhookApplicationServerFunctional(createApplicationWithWebhook(overrides: [
|
||||
'git_repository' => 'git@10.0.0.80:2222/other-org/test-repo.git',
|
||||
]));
|
||||
|
||||
test('github matches an ssh repository URL with a non-git username', function () {
|
||||
$app = createApplicationWithWebhook(overrides: [
|
||||
'git_repository' => 'custom-user@git.example.com:test-org/test-repo.git',
|
||||
]);
|
||||
$secret = $app->manual_webhook_secret_github;
|
||||
sendManualWebhookPush($this, $provider, $application)->assertOk();
|
||||
|
||||
$payload = json_encode([
|
||||
'ref' => 'refs/heads/main',
|
||||
'repository' => ['full_name' => 'test-org/test-repo'],
|
||||
'after' => 'abc1234',
|
||||
'commits' => [],
|
||||
]);
|
||||
|
||||
$response = $this->call('POST', '/webhooks/source/github/events/manual', [], [], [], [
|
||||
'HTTP_X-GitHub-Event' => 'push',
|
||||
'HTTP_X-Hub-Signature-256' => 'sha256='.hash_hmac('sha256', $payload, $secret),
|
||||
'CONTENT_TYPE' => 'application/json',
|
||||
], $payload);
|
||||
|
||||
$response->assertOk();
|
||||
expect($response->getContent())->not->toContain('No applications found');
|
||||
});
|
||||
|
||||
test('github matches an ssh repository URL with a non-git username and custom port', function () {
|
||||
$app = createApplicationWithWebhook(overrides: [
|
||||
'git_repository' => 'custom-user@git.example.com:2222/test-org/test-repo.git',
|
||||
]);
|
||||
$secret = $app->manual_webhook_secret_github;
|
||||
|
||||
$payload = json_encode([
|
||||
'ref' => 'refs/heads/main',
|
||||
'repository' => ['full_name' => 'test-org/test-repo'],
|
||||
'after' => 'abc1234',
|
||||
'commits' => [],
|
||||
]);
|
||||
|
||||
$response = $this->call('POST', '/webhooks/source/github/events/manual', [], [], [], [
|
||||
'HTTP_X-GitHub-Event' => 'push',
|
||||
'HTTP_X-Hub-Signature-256' => 'sha256='.hash_hmac('sha256', $payload, $secret),
|
||||
'CONTENT_TYPE' => 'application/json',
|
||||
], $payload);
|
||||
|
||||
$response->assertOk();
|
||||
expect($response->getContent())->not->toContain('No applications found');
|
||||
});
|
||||
|
||||
test('gitlab matches scp-style ssh repository URL with custom port', function () {
|
||||
$app = createApplicationWithWebhook(overrides: [
|
||||
'git_repository' => 'git@gitlab.example.com:2222/services/xyz.git',
|
||||
'git_branch' => 'master',
|
||||
]);
|
||||
$secret = $app->manual_webhook_secret_gitlab;
|
||||
|
||||
$response = $this->postJson('/webhooks/source/gitlab/events/manual', [
|
||||
'object_kind' => 'push',
|
||||
'ref' => 'refs/heads/master',
|
||||
'project' => ['path_with_namespace' => 'services/xyz'],
|
||||
'after' => 'abc1234',
|
||||
'commits' => [],
|
||||
], [
|
||||
'X-Gitlab-Token' => $secret,
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
expect($response->getContent())->not->toContain('No applications found');
|
||||
});
|
||||
|
||||
test('gitlab matches scp-style ssh repository URL without port', function () {
|
||||
$app = createApplicationWithWebhook(overrides: [
|
||||
'git_repository' => 'git@gitlab.example.com:services/xyz.git',
|
||||
'git_branch' => 'master',
|
||||
]);
|
||||
$secret = $app->manual_webhook_secret_gitlab;
|
||||
|
||||
$response = $this->postJson('/webhooks/source/gitlab/events/manual', [
|
||||
'object_kind' => 'push',
|
||||
'ref' => 'refs/heads/master',
|
||||
'project' => ['path_with_namespace' => 'services/xyz'],
|
||||
'after' => 'abc1234',
|
||||
'commits' => [],
|
||||
], [
|
||||
'X-Gitlab-Token' => $secret,
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
expect($response->getContent())->not->toContain('No applications found');
|
||||
});
|
||||
|
||||
test('github matches repository case-insensitively', function () {
|
||||
$app = createApplicationWithWebhook(overrides: [
|
||||
'git_repository' => 'https://github.com/Test-Org/Test-Repo.git',
|
||||
]);
|
||||
$secret = $app->manual_webhook_secret_github;
|
||||
|
||||
$payload = json_encode([
|
||||
'ref' => 'refs/heads/main',
|
||||
'repository' => ['full_name' => 'test-org/test-repo'],
|
||||
'after' => 'abc1234',
|
||||
'commits' => [],
|
||||
]);
|
||||
|
||||
$response = $this->call('POST', '/webhooks/source/github/events/manual', [], [], [], [
|
||||
'HTTP_X-GitHub-Event' => 'push',
|
||||
'HTTP_X-Hub-Signature-256' => 'sha256='.hash_hmac('sha256', $payload, $secret),
|
||||
'CONTENT_TYPE' => 'application/json',
|
||||
], $payload);
|
||||
|
||||
$response->assertOk();
|
||||
expect($response->getContent())->not->toContain('No applications found');
|
||||
});
|
||||
expect(ApplicationDeploymentQueue::query()->where('application_id', $application->id)->exists())->toBeFalse();
|
||||
})->with(['github', 'gitlab', 'bitbucket', 'gitea']);
|
||||
});
|
||||
|
||||
describe('Webhook Secret Auto-Generation', function () {
|
||||
|
||||
@@ -5,6 +5,7 @@ use App\Models\InstanceSettings;
|
||||
use App\Models\LocalPersistentVolume;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
@@ -135,6 +136,42 @@ it('saves application name description and ports from the general form', functio
|
||||
->screenshot(filename: 'application-general-reloaded');
|
||||
});
|
||||
|
||||
it('shows the unsaved bar for a Compose location edit and saves it with the name', function () {
|
||||
Process::fake(fn ($process) => match (true) {
|
||||
str_contains($process->command, 'git --version') => Process::result('git version 2.43.0'),
|
||||
str_contains($process->command, 'head -c') => Process::result("services:\n web:\n image: nginx\n"),
|
||||
default => Process::result(''),
|
||||
});
|
||||
$this->application->update([
|
||||
'build_pack' => 'dockercompose',
|
||||
'docker_compose_location' => '/docker-compose.yaml',
|
||||
'docker_compose_raw' => "services:\n web:\n image: nginx\n",
|
||||
]);
|
||||
loginAndSkipBoarding();
|
||||
|
||||
$page = visit(applicationConfigurationUrl(
|
||||
$this->stack['project'],
|
||||
$this->stack['environment'],
|
||||
$this->application
|
||||
));
|
||||
|
||||
// The Compose location input is bound through @entangle, not wire:model.
|
||||
$page->assertSee('Docker compose location')
|
||||
->type('input[placeholder="/docker-compose.yaml"]', '/compose.prod.yaml')
|
||||
->assertScript(<<<'JS'
|
||||
() => [...document.querySelectorAll('.is-dirty')].some((bar) => bar.textContent.includes('Save changes'))
|
||||
JS)
|
||||
->type('name', 'Renamed Compose App')
|
||||
->click('button:visible:has-text("Save changes")')
|
||||
->wait(2)
|
||||
->screenshot(filename: 'application-compose-location-saved');
|
||||
|
||||
expect($this->application->refresh()->only(['name', 'docker_compose_location']))->toBe([
|
||||
'name' => 'Renamed Compose App',
|
||||
'docker_compose_location' => '/compose.prod.yaml',
|
||||
]);
|
||||
});
|
||||
|
||||
it('saves custom docker run options from the UI', function () {
|
||||
loginAndSkipBoarding();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user