Skip to content

Commit 047aff1

Browse files
authored
feat: refresh repos on private github app (#8621)
2 parents 2692496 + 7638912 commit 047aff1

File tree

3 files changed

+177
-6
lines changed

3 files changed

+177
-6
lines changed

app/Livewire/Project/New/GithubPrivateRepository.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ public function updatedBuildPack()
9999
public function loadRepositories($github_app_id)
100100
{
101101
$this->repositories = collect();
102+
$this->branches = collect();
103+
$this->total_branches_count = 0;
102104
$this->page = 1;
103105
$this->selected_github_app_id = $github_app_id;
104106
$this->github_app = GithubApp::where('id', $github_app_id)->first();

resources/views/livewire/project/new/github-private-repository.blade.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
<livewire:source.github.create />
66
</x-modal-input>
77
@if ($repositories->count() > 0)
8-
<a target="_blank" class="flex hover:no-underline" href="{{ getInstallationPath($github_app) }}">
9-
<x-forms.button>
10-
Change Repositories on GitHub
11-
<x-external-link />
12-
</x-forms.button>
8+
<x-forms.button wire:click.prevent="loadRepositories({{ $github_app->id }})">
9+
Refresh Repository List
10+
</x-forms.button>
11+
<a target="_blank" class="inline-flex items-center self-center gap-1 text-sm hover:underline dark:text-neutral-400"
12+
href="{{ getInstallationPath($github_app) }}">
13+
Change Repositories on GitHub
14+
<x-external-link />
1315
</a>
1416
@endif
1517
</div>
@@ -51,7 +53,10 @@
5153
@endforeach
5254
</x-forms.datalist>
5355
</div>
54-
<x-forms.button wire:click.prevent="loadBranches"> Load Repository </x-forms.button>
56+
<x-forms.button :showLoadingIndicator="false" wire:click.prevent="loadBranches" wire:target="loadBranches, selected_repository_id">
57+
Load Repository
58+
<x-loading-on-button wire:loading.delay wire:target="loadBranches, selected_repository_id" />
59+
</x-forms.button>
5560
</div>
5661
@else
5762
<div>No repositories found. Check your GitHub App configuration.</div>
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
<?php
2+
3+
use App\Livewire\Project\New\GithubPrivateRepository;
4+
use App\Models\GithubApp;
5+
use App\Models\PrivateKey;
6+
use App\Models\Team;
7+
use App\Models\User;
8+
use Illuminate\Foundation\Testing\RefreshDatabase;
9+
use Illuminate\Support\Facades\Http;
10+
use Livewire\Livewire;
11+
12+
uses(RefreshDatabase::class);
13+
14+
beforeEach(function () {
15+
$this->team = Team::factory()->create();
16+
$this->user = User::factory()->create();
17+
$this->team->members()->attach($this->user->id, ['role' => 'owner']);
18+
19+
$this->actingAs($this->user);
20+
session(['currentTeam' => $this->team]);
21+
22+
$this->rsaKey = openssl_pkey_new([
23+
'private_key_bits' => 2048,
24+
'private_key_type' => OPENSSL_KEYTYPE_RSA,
25+
]);
26+
openssl_pkey_export($this->rsaKey, $pemKey);
27+
28+
$this->privateKey = PrivateKey::create([
29+
'name' => 'Test Key',
30+
'private_key' => $pemKey,
31+
'team_id' => $this->team->id,
32+
]);
33+
34+
$this->githubApp = GithubApp::forceCreate([
35+
'name' => 'Test GitHub App',
36+
'api_url' => 'https://api.github.com',
37+
'html_url' => 'https://github.com',
38+
'custom_user' => 'git',
39+
'custom_port' => 22,
40+
'app_id' => 12345,
41+
'installation_id' => 67890,
42+
'client_id' => 'test-client-id',
43+
'client_secret' => 'test-client-secret',
44+
'webhook_secret' => 'test-webhook-secret',
45+
'private_key_id' => $this->privateKey->id,
46+
'team_id' => $this->team->id,
47+
'is_system_wide' => false,
48+
]);
49+
});
50+
51+
function fakeGithubHttp(array $repositories): void
52+
{
53+
Http::fake([
54+
'https://api.github.com/zen' => Http::response('Keep it logically awesome.', 200, [
55+
'Date' => now()->toRfc7231String(),
56+
]),
57+
'https://api.github.com/app/installations/67890/access_tokens' => Http::response([
58+
'token' => 'fake-installation-token',
59+
], 201),
60+
'https://api.github.com/installation/repositories*' => Http::response([
61+
'total_count' => count($repositories),
62+
'repositories' => $repositories,
63+
], 200),
64+
]);
65+
}
66+
67+
describe('GitHub Private Repository Component', function () {
68+
test('loadRepositories fetches and displays repositories', function () {
69+
$repos = [
70+
['id' => 1, 'name' => 'alpha-repo', 'owner' => ['login' => 'testuser']],
71+
['id' => 2, 'name' => 'beta-repo', 'owner' => ['login' => 'testuser']],
72+
];
73+
74+
fakeGithubHttp($repos);
75+
76+
Livewire::test(GithubPrivateRepository::class, ['type' => 'private-gh-app'])
77+
->assertSet('current_step', 'github_apps')
78+
->call('loadRepositories', $this->githubApp->id)
79+
->assertSet('current_step', 'repository')
80+
->assertSet('total_repositories_count', 2)
81+
->assertSet('selected_repository_id', 1);
82+
});
83+
84+
test('loadRepositories can be called again to refresh the repository list', function () {
85+
$initialRepos = [
86+
['id' => 1, 'name' => 'alpha-repo', 'owner' => ['login' => 'testuser']],
87+
];
88+
89+
$updatedRepos = [
90+
['id' => 1, 'name' => 'alpha-repo', 'owner' => ['login' => 'testuser']],
91+
['id' => 2, 'name' => 'beta-repo', 'owner' => ['login' => 'testuser']],
92+
['id' => 3, 'name' => 'gamma-repo', 'owner' => ['login' => 'testuser']],
93+
];
94+
95+
$callCount = 0;
96+
Http::fake([
97+
'https://api.github.com/zen' => Http::response('Keep it logically awesome.', 200, [
98+
'Date' => now()->toRfc7231String(),
99+
]),
100+
'https://api.github.com/app/installations/67890/access_tokens' => Http::response([
101+
'token' => 'fake-installation-token',
102+
], 201),
103+
'https://api.github.com/installation/repositories*' => function () use (&$callCount, $initialRepos, $updatedRepos) {
104+
$callCount++;
105+
$repos = $callCount === 1 ? $initialRepos : $updatedRepos;
106+
107+
return Http::response([
108+
'total_count' => count($repos),
109+
'repositories' => $repos,
110+
], 200);
111+
},
112+
]);
113+
114+
$component = Livewire::test(GithubPrivateRepository::class, ['type' => 'private-gh-app'])
115+
->call('loadRepositories', $this->githubApp->id)
116+
->assertSet('total_repositories_count', 1);
117+
118+
// Simulate new repos becoming available after changing access on GitHub
119+
$component
120+
->call('loadRepositories', $this->githubApp->id)
121+
->assertSet('total_repositories_count', 3)
122+
->assertSet('current_step', 'repository');
123+
});
124+
125+
test('loadRepositories resets branches when refreshing', function () {
126+
$repos = [
127+
['id' => 1, 'name' => 'alpha-repo', 'owner' => ['login' => 'testuser']],
128+
];
129+
130+
fakeGithubHttp($repos);
131+
132+
$component = Livewire::test(GithubPrivateRepository::class, ['type' => 'private-gh-app'])
133+
->call('loadRepositories', $this->githubApp->id);
134+
135+
// Manually set branches to simulate a previous branch load
136+
$component->set('branches', collect([['name' => 'main'], ['name' => 'develop']]));
137+
$component->set('total_branches_count', 2);
138+
139+
// Refresh repositories should reset branches
140+
fakeGithubHttp($repos);
141+
142+
$component
143+
->call('loadRepositories', $this->githubApp->id)
144+
->assertSet('total_branches_count', 0)
145+
->assertSet('branches', collect());
146+
});
147+
148+
test('refresh button is visible when repositories are loaded', function () {
149+
$repos = [
150+
['id' => 1, 'name' => 'alpha-repo', 'owner' => ['login' => 'testuser']],
151+
];
152+
153+
fakeGithubHttp($repos);
154+
155+
Livewire::test(GithubPrivateRepository::class, ['type' => 'private-gh-app'])
156+
->call('loadRepositories', $this->githubApp->id)
157+
->assertSee('Refresh Repository List');
158+
});
159+
160+
test('refresh button is not visible before repositories are loaded', function () {
161+
Livewire::test(GithubPrivateRepository::class, ['type' => 'private-gh-app'])
162+
->assertDontSee('Refresh Repository List');
163+
});
164+
});

0 commit comments

Comments
 (0)