Merge remote-tracking branch 'origin/next' into ghe-support-helpers

This commit is contained in:
Andras Bacsai
2026-07-03 10:26:58 +02:00
3 changed files with 240 additions and 65 deletions
@@ -147,7 +147,111 @@ describe('GitHub Source Change Component', function () {
]);
});
test('ghe dot com installation path includes encoded organization segment', function () {
test('ghe.com installation path uses github cloud owner scoped route', function () {
$githubApp = new GithubApp;
$githubApp->forceFill([
'id' => 123,
'name' => 'provided-github-app',
'organization' => 'acme-enterprise',
'html_url' => 'https://octocorp.ghe.com',
'team_id' => 456,
]);
$installationUrl = getInstallationPath($githubApp);
parse_str(parse_url($installationUrl, PHP_URL_QUERY), $query);
$installState = $query['state'] ?? null;
expect($installationUrl)->toStartWith('https://octocorp.ghe.com/apps/acme-enterprise/provided-github-app/installations/new?')
->and($installState)->not->toBeEmpty()
->and(Cache::get('github-app-setup-state:'.hash('sha256', $installState)))
->toMatchArray([
'action' => 'install',
'github_app_id' => 123,
'team_id' => 456,
]);
});
test('installation path is pure and never calls github or mutates the app', function () {
Http::fake();
$privateKey = PrivateKey::create([
'name' => 'github-app-local-name',
'private_key' => validPrivateKey(),
'team_id' => $this->team->id,
'is_git_related' => true,
]);
$githubApp = GithubApp::create([
'name' => 'Local Display Name',
'organization' => 'acme-enterprise',
'api_url' => 'https://api.github.com',
'html_url' => 'https://octocorp.ghe.com',
'custom_user' => 'git',
'custom_port' => 22,
'app_id' => 12345,
'private_key_id' => $privateKey->id,
'team_id' => $this->team->id,
'is_system_wide' => false,
]);
$installationUrl = getInstallationPath($githubApp);
Http::assertNothingSent();
expect($installationUrl)->toStartWith('https://octocorp.ghe.com/apps/acme-enterprise/local-display-name/installations/new?')
->and($githubApp->refresh()->name)->toBe('Local Display Name')
->and($privateKey->refresh()->name)->toBe('github-app-local-name');
});
test('syncGithubAppName persists the github slug and renames the private key', function () {
Http::fake([
'*/app' => Http::response(['slug' => 'actual-github-slug']),
'*/zen' => Http::response('Keep it logically awesome.'),
]);
$privateKey = PrivateKey::create([
'name' => 'github-app-local-name',
'private_key' => validPrivateKey(),
'team_id' => $this->team->id,
'is_git_related' => true,
]);
$githubApp = GithubApp::create([
'name' => 'Local Display Name',
'organization' => 'acme-enterprise',
'api_url' => 'https://api.github.com',
'html_url' => 'https://octocorp.ghe.com',
'custom_user' => 'git',
'custom_port' => 22,
'app_id' => 12345,
'private_key_id' => $privateKey->id,
'team_id' => $this->team->id,
'is_system_wide' => false,
]);
$appSlug = syncGithubAppName($githubApp, true);
expect($appSlug)->toBe('actual-github-slug')
->and($githubApp->refresh()->name)->toBe('actual-github-slug')
->and($privateKey->refresh()->name)->toBe('github-app-actual-github-slug');
});
test('ghe.com installation path encodes the organization segment', function () {
$githubApp = new GithubApp;
$githubApp->forceFill([
'id' => 123,
'name' => 'provided-github-app',
'organization' => '/acme enterprise/',
'html_url' => 'https://octocorp.ghe.com',
'team_id' => 456,
]);
$installationUrl = getInstallationPath($githubApp);
expect($installationUrl)->toStartWith('https://octocorp.ghe.com/apps/acme%20enterprise/provided-github-app/installations/new?');
});
test('ghe.com installation path encodes plus signs in the organization segment', function () {
$githubApp = new GithubApp;
$githubApp->forceFill([
'id' => 123,
@@ -157,8 +261,24 @@ describe('GitHub Source Change Component', function () {
'team_id' => 456,
]);
expect(getInstallationPath($githubApp))
->toStartWith('https://octocorp.ghe.com/apps/octo%2Bcorp/provided-git-hub-app/installations/new?');
$installationUrl = getInstallationPath($githubApp);
expect($installationUrl)->toStartWith('https://octocorp.ghe.com/apps/octo%2Bcorp/provided-git-hub-app/installations/new?');
});
test('ghe.com installation path keeps app scoped fallback when organization is blank', function () {
$githubApp = new GithubApp;
$githubApp->forceFill([
'id' => 123,
'name' => 'provided-github-app',
'organization' => null,
'html_url' => 'https://octocorp.ghe.com',
'team_id' => 456,
]);
$installationUrl = getInstallationPath($githubApp);
expect($installationUrl)->toStartWith('https://octocorp.ghe.com/apps/provided-github-app/installations/new?');
});
test('defaults webhook endpoint to app url when it is the first available endpoint', function () {
@@ -221,6 +341,10 @@ describe('GitHub Source Change Component', function () {
});
test('can mount with fully configured github app', function () {
Http::fake([
'https://api.github.com/app' => Http::response(['slug' => 'test-github-app']),
]);
$privateKey = PrivateKey::create([
'name' => 'Test Key',
'private_key' => validPrivateKey(),
@@ -255,6 +379,10 @@ describe('GitHub Source Change Component', function () {
});
test('can update github app from null to valid values', function () {
Http::fake([
'https://api.github.com/app' => Http::response(['slug' => 'test-github-app']),
]);
$privateKey = PrivateKey::create([
'name' => 'Test Key',
'private_key' => validPrivateKey(),
@@ -291,10 +419,10 @@ describe('GitHub Source Change Component', function () {
expect($githubApp->private_key_id)->toBe($privateKey->id);
});
test('normalizes ghe dot com api url when saving github app settings', function () {
test('normalizes resolvable ghe dot com api url when saving github app settings', function () {
$githubApp = GithubApp::create([
'name' => 'Test GitHub App',
'api_url' => 'https://octocorp.ghe.com/api/v3',
'api_url' => 'https://github.ghe.com/api/v3',
'html_url' => 'https://github.com',
'custom_user' => 'git',
'custom_port' => 22,
@@ -305,14 +433,14 @@ describe('GitHub Source Change Component', function () {
Livewire::withQueryParams(['github_app_uuid' => $githubApp->uuid])
->test(Change::class)
->assertSuccessful()
->set('htmlUrl', 'https://octocorp.ghe.com')
->set('apiUrl', 'https://octocorp.ghe.com/api/v3')
->set('htmlUrl', 'https://github.ghe.com')
->set('apiUrl', 'https://github.ghe.com/api/v3')
->call('submit')
->assertDispatched('success')
->assertSet('apiUrl', 'https://api.octocorp.ghe.com');
->assertSet('apiUrl', 'https://api.github.ghe.com');
$githubApp->refresh();
expect($githubApp->api_url)->toBe('https://api.octocorp.ghe.com');
expect($githubApp->api_url)->toBe('https://api.github.ghe.com');
});
test('rejects invalid github organization values', function () {
@@ -487,7 +615,7 @@ describe('GitHub Source Change Component', function () {
->and($githubApp->pull_requests)->toBe('write');
});
test('sync name uses normalized ghe dot com api url', function () {
test('sync name uses normalized resolvable ghe dot com api url', function () {
$privateKey = PrivateKey::create([
'name' => 'Test Key',
'private_key' => validPrivateKey(),
@@ -496,8 +624,8 @@ describe('GitHub Source Change Component', function () {
$githubApp = GithubApp::create([
'name' => 'Test GitHub App',
'api_url' => 'https://api.octocorp.ghe.com',
'html_url' => 'https://octocorp.ghe.com',
'api_url' => 'https://api.github.ghe.com',
'html_url' => 'https://github.ghe.com',
'custom_user' => 'git',
'custom_port' => 22,
'app_id' => 12345,
@@ -509,7 +637,10 @@ describe('GitHub Source Change Component', function () {
Http::preventStrayRequests();
Http::fake([
'https://api.octocorp.ghe.com/app' => Http::response([
'https://api.github.ghe.com/zen' => Http::response('Keep it logically awesome.', 200, [
'date' => now()->toRfc7231String(),
]),
'https://api.github.ghe.com/app' => Http::response([
'slug' => 'octocorp-app',
]),
]);
@@ -520,6 +651,6 @@ describe('GitHub Source Change Component', function () {
->call('updateGithubAppName')
->assertDispatched('success');
Http::assertSent(fn ($request) => $request->url() === 'https://api.octocorp.ghe.com/app');
Http::assertSent(fn ($request) => $request->url() === 'https://api.github.ghe.com/app');
});
});