feat: installation/update github apps
This commit is contained in:
parent
db92dc3636
commit
19ad184cd6
@ -35,7 +35,7 @@ public function changePrivateKey()
|
||||
$this->private_key->save();
|
||||
session('currentTeam')->privateKeys = PrivateKey::where('team_id', session('currentTeam')->id)->get();
|
||||
} catch (\Exception $e) {
|
||||
return generalErrorHandlerLivewire($e, $this);
|
||||
return generalErrorHandler($e, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ public function submit($data)
|
||||
$this->application->refresh();
|
||||
$this->emit('clearAddEnv');
|
||||
} catch (\Exception $e) {
|
||||
return generalErrorHandlerLivewire($e, $this);
|
||||
return generalErrorHandler($e, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public function submit($data)
|
||||
$this->application->refresh();
|
||||
$this->emit('clearAddStorage');
|
||||
} catch (\Exception $e) {
|
||||
return generalErrorHandlerLivewire($e, $this);
|
||||
return generalErrorHandler($e, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
25
app/Http/Livewire/Project/Delete.php
Normal file
25
app/Http/Livewire/Project/Delete.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project;
|
||||
|
||||
use App\Models\Project;
|
||||
use Livewire\Component;
|
||||
|
||||
class Delete extends Component
|
||||
{
|
||||
public int $project_id;
|
||||
public int $resource_count = 0;
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$this->validate([
|
||||
'project_id' => 'required|int',
|
||||
]);
|
||||
$project = Project::findOrFail($this->project_id);
|
||||
if ($project->applications->count() > 0) {
|
||||
return $this->emit('error', 'Project has applications, please delete them first.');
|
||||
}
|
||||
$project->delete();
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ class GithubPrivateRepository extends Component
|
||||
public $github_apps;
|
||||
public GithubApp $github_app;
|
||||
public $parameters;
|
||||
public $type;
|
||||
|
||||
public int $selected_repository_id;
|
||||
public string $selected_repository_owner;
|
||||
@ -110,8 +111,16 @@ public function loadDestinations()
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
|
||||
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
|
||||
if ($this->type === 'project') {
|
||||
$project = Project::create([
|
||||
'name' => generateRandomName(),
|
||||
'team_id' => session('currentTeam')->id
|
||||
]);
|
||||
$environment = $project->load(['environments'])->environments->first();
|
||||
} else {
|
||||
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
|
||||
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
|
||||
}
|
||||
$application = Application::create([
|
||||
'name' => "{$this->selected_repository_owner}/{$this->selected_repository_repo}:{$this->selected_branch_name}",
|
||||
'git_repository' => "{$this->selected_repository_owner}/{$this->selected_repository_repo}",
|
||||
@ -130,7 +139,7 @@ public function submit()
|
||||
'environment_name' => $environment->name
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return generalErrorHandlerLivewire($e, $this);
|
||||
return generalErrorHandler($e, $this);
|
||||
}
|
||||
}
|
||||
public function mount()
|
||||
|
@ -54,7 +54,7 @@ public function checkServer()
|
||||
$this->dockerComposeVersion = 'Not installed.';
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return generalErrorHandlerLivewire($e, $this);
|
||||
return generalErrorHandler($e, $this);
|
||||
}
|
||||
}
|
||||
public function delete()
|
||||
|
@ -31,7 +31,7 @@ public function createGitHubApp()
|
||||
"custom_port" => 'required|int',
|
||||
"is_system_wide" => 'required|bool',
|
||||
]);
|
||||
GithubApp::create([
|
||||
$github_app = GithubApp::create([
|
||||
'name' => $this->name,
|
||||
'organization' => $this->organization,
|
||||
'api_url' => $this->api_url,
|
||||
@ -41,8 +41,9 @@ public function createGitHubApp()
|
||||
'is_system_wide' => $this->is_system_wide,
|
||||
'team_id' => session('currentTeam')->id,
|
||||
]);
|
||||
redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
|
||||
} catch (\Exception $e) {
|
||||
return generalErrorHandlerLivewire($e, $this);
|
||||
return generalErrorHandler($e, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ public function submit()
|
||||
$this->validate();
|
||||
$this->github_app->save();
|
||||
} catch (\Exception $e) {
|
||||
return generalErrorHandlerLivewire($e, $this);
|
||||
return generalErrorHandler($e, $this);
|
||||
}
|
||||
}
|
||||
public function instantSave()
|
||||
@ -46,7 +46,7 @@ public function instantSave()
|
||||
$this->github_app->save();
|
||||
$this->emit('saved', 'GitHub settings updated!');
|
||||
} catch (\Exception $e) {
|
||||
return generalErrorHandlerLivewire($e, $this);
|
||||
return generalErrorHandler($e, $this);
|
||||
}
|
||||
}
|
||||
public function mount()
|
||||
@ -64,7 +64,7 @@ public function delete()
|
||||
$this->github_app->delete();
|
||||
redirect()->route('dashboard');
|
||||
} catch (\Exception $e) {
|
||||
return generalErrorHandlerLivewire($e, $this);
|
||||
return generalErrorHandler($e, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,9 @@ public function boot(): void
|
||||
->prefix('api')
|
||||
->group(base_path('routes/api.php'));
|
||||
|
||||
Route::prefix('webhooks')
|
||||
->group(base_path('routes/webhooks.php'));
|
||||
|
||||
Route::middleware('web')
|
||||
->group(base_path('routes/web.php'));
|
||||
});
|
||||
|
@ -14,19 +14,23 @@
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Spatie\Activitylog\Contracts\Activity;
|
||||
|
||||
if (!function_exists('generalErrorHandlerLivewire')) {
|
||||
function generalErrorHandlerLivewire(\Throwable $e, $that)
|
||||
if (!function_exists('generalErrorHandler')) {
|
||||
function generalErrorHandler(\Throwable $e, $that = null)
|
||||
{
|
||||
if ($e instanceof QueryException) {
|
||||
if ($e->errorInfo[0] === '23505') {
|
||||
$that->emit('error', 'Duplicate entry found.');
|
||||
} else if (count($e->errorInfo) === 4) {
|
||||
$that->emit('error', $e->errorInfo[3]);
|
||||
if ($that) {
|
||||
if ($e instanceof QueryException) {
|
||||
if ($e->errorInfo[0] === '23505') {
|
||||
$that->emit('error', 'Duplicate entry found.');
|
||||
} else if (count($e->errorInfo) === 4) {
|
||||
$that->emit('error', $e->errorInfo[3]);
|
||||
} else {
|
||||
$that->emit('error', $e->errorInfo[2]);
|
||||
}
|
||||
} else {
|
||||
$that->emit('error', $e->errorInfo[2]);
|
||||
$that->emit('error', $e->getMessage());
|
||||
}
|
||||
} else {
|
||||
$that->emit('error', $e);
|
||||
dump($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,25 @@
|
||||
@props([
|
||||
'isWarning' => null,
|
||||
'disabled' => null,
|
||||
'defaultClass' => 'text-white bg-neutral-800 hover:bg-violet-600 h-8',
|
||||
'defaultWarningClass' => 'text-white bg-red-500 hover:bg-red-600 h-8',
|
||||
'disabledClass' => 'text-neutral-400 bg-neutral-900 h-8',
|
||||
'loadingClass' => 'text-black bg-green-500 h-8',
|
||||
'confirm' => null,
|
||||
'confirmAction' => null,
|
||||
])
|
||||
<button {{ $attributes }} @class([
|
||||
$defaultClass => !$confirm && !$isWarning,
|
||||
$defaultWarningClass => $confirm || $isWarning,
|
||||
]) @if ($attributes->whereStartsWith('wire:click'))
|
||||
$defaultClass => !$confirm && !$isWarning && !$disabled,
|
||||
$defaultWarningClass => ($confirm || $isWarning) && !$disabled,
|
||||
$disabledClass => $disabled,
|
||||
]) @if ($attributes->whereStartsWith('wire:click') && !$disabled)
|
||||
wire:target="{{ explode('(', $attributes->whereStartsWith('wire:click')->first())[0] }}"
|
||||
wire:loading.delay.class="{{ $loadingClass }}" wire:loading.delay.attr="disabled"
|
||||
wire:loading.delay.class.remove="{{ $defaultClass }} {{ $attributes->whereStartsWith('class')->first() }}"
|
||||
@endif
|
||||
@if ($disabled !== null)
|
||||
disabled title="{{ $disabled }}"
|
||||
@endif
|
||||
@isset($confirm)
|
||||
x-on:click="toggleConfirmModal('{{ $confirm }}', '{{ explode('(', $confirmAction)[0] }}')"
|
||||
@endisset
|
||||
|
13
resources/views/livewire/project/delete.blade.php
Normal file
13
resources/views/livewire/project/delete.blade.php
Normal file
@ -0,0 +1,13 @@
|
||||
<div x-data="{ deleteProject: false }">
|
||||
<x-naked-modal show="deleteProject" message='Are you sure you would like to delete this project?' />
|
||||
@if ($resource_count > 0)
|
||||
<x-inputs.button isWarning disabled="First delete all resources.">
|
||||
Delete
|
||||
</x-inputs.button>
|
||||
@else
|
||||
<x-inputs.button isWarning x-on:click.prevent="deleteProject = true">
|
||||
Delete
|
||||
</x-inputs.button>
|
||||
@endif
|
||||
|
||||
</div>
|
@ -2,7 +2,9 @@
|
||||
@if ($github_apps->count() > 0)
|
||||
<h1>Choose a GitHub App</h1>
|
||||
@foreach ($github_apps as $ghapp)
|
||||
<x-inputs.button wire:click="loadRepositories({{ $ghapp->id }})">{{ $ghapp->name }}</x-inputs.button>
|
||||
<x-inputs.button wire:key="{{ $ghapp->id }}" wire:click="loadRepositories({{ $ghapp->id }})">
|
||||
{{ $ghapp->name }}
|
||||
</x-inputs.button>
|
||||
@endforeach
|
||||
<div>
|
||||
@if ($repositories->count() > 0)
|
||||
|
@ -21,6 +21,9 @@
|
||||
<x-inputs.input id="github_app.client_secret" label="Client Secret" type="password" disabled />
|
||||
<x-inputs.input id="github_app.webhook_secret" label="Webhook Secret" type="password" disabled />
|
||||
<x-inputs.button type="submit">Save</x-inputs.button>
|
||||
<x-inputs.button isWarning x-on:click.prevent="deleteSource = true">
|
||||
Delete
|
||||
</x-inputs.button>
|
||||
@else
|
||||
<div class="py-2">
|
||||
<x-inputs.button type="submit">Save</x-inputs.button>
|
||||
@ -30,6 +33,4 @@
|
||||
</div>
|
||||
@endif
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -18,7 +18,7 @@
|
||||
<livewire:project.new.public-git-repository :type="$type" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'github-private-repo'">
|
||||
<livewire:project.new.github-private-repository />
|
||||
<livewire:project.new.github-private-repository :type="$type" />
|
||||
</div>
|
||||
</div>
|
||||
</x-layout>
|
||||
|
@ -1,8 +1,14 @@
|
||||
<x-layout>
|
||||
<h1>Resources <a href="{{ route('project.resources.new', Route::current()->parameters()) }}">
|
||||
<div class="flex items-center gap-2">
|
||||
<h1>Resources</h1>
|
||||
<a href="{{ route('project.resources.new', Route::current()->parameters()) }}">
|
||||
<x-inputs.button>New</x-inputs.button>
|
||||
</a>
|
||||
</h1>
|
||||
<livewire:project.delete :project_id="$project->id" :resource_count="$project->applications->count()" />
|
||||
</div>
|
||||
@if ($environment->applications->count() === 0)
|
||||
<p>No resources yet.</p>
|
||||
@endif
|
||||
<div>
|
||||
@foreach ($environment->applications as $application)
|
||||
<p>
|
||||
|
@ -25,13 +25,14 @@ function createGithubApp() {
|
||||
name,
|
||||
url: baseUrl,
|
||||
hook_attributes: {
|
||||
url: `${webhookBaseUrl}/github/events`
|
||||
url: `${webhookBaseUrl}/source/github/events`,
|
||||
active: true,
|
||||
},
|
||||
redirect_url: `${webhookBaseUrl}/github`,
|
||||
redirect_url: `${webhookBaseUrl}/source/github/redirect`,
|
||||
callback_urls: [`${baseUrl}/login/github/app`],
|
||||
public: false,
|
||||
request_oauth_on_install: false,
|
||||
setup_url: `${webhookBaseUrl}/github/install?source=${uuid}`,
|
||||
setup_url: `${webhookBaseUrl}/source/github/install?source=${uuid}`,
|
||||
setup_on_update: true,
|
||||
default_permissions: {
|
||||
contents: 'read',
|
||||
@ -54,5 +55,14 @@ function createGithubApp() {
|
||||
form.submit();
|
||||
}
|
||||
</script>
|
||||
@elseif($github_app->app_id && !$github_app->installation_id)
|
||||
<a href="{{ $installation_url }}">
|
||||
<x-inputs.button>Install Repositories</x-inputs.button>
|
||||
</a>
|
||||
@elseif($github_app->app_id && $github_app->installation_id)
|
||||
<a href="{{ $installation_url }}">
|
||||
<x-inputs.button>Update Repositories</x-inputs.button>
|
||||
</a>
|
||||
@endif
|
||||
|
||||
</x-layout>
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Models\GithubApp;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
@ -17,6 +18,13 @@
|
||||
Route::get('/health', function () {
|
||||
return 'OK';
|
||||
});
|
||||
Route::get('/webhooks/source/github/redirect', function () {
|
||||
$code = request()->get('code');
|
||||
$state = request()->get('state');
|
||||
$github_app = GithubApp::where('uuid', $state)->firstOrFail();
|
||||
return 'OK';
|
||||
});
|
||||
|
||||
// Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
|
||||
// return $request->user();
|
||||
// });
|
||||
|
@ -85,16 +85,20 @@
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
Route::get('/source/new', fn () => view('source.new'))->name('source.new');
|
||||
Route::get('/source/github/{github_app_uuid}', function (Request $request) {
|
||||
$github_app = GithubApp::where('uuid', request()->github_app_uuid)->first();
|
||||
$name = Str::kebab('coolify' . $github_app->name);
|
||||
$settings = InstanceSettings::first();
|
||||
$host = $request->schemeAndHttpHost();
|
||||
if ($settings->fqdn) {
|
||||
$host = $settings->fqdn;
|
||||
}
|
||||
$github_app = GithubApp::where('uuid', request()->github_app_uuid)->first();
|
||||
$installation_path = $github_app->html_url === 'https://github.com' ? 'apps' : 'github-apps';
|
||||
$installation_url = "$github_app->html_url/$installation_path/$name/installations/new";
|
||||
return view('source.github.show', [
|
||||
'github_app' => $github_app,
|
||||
'host' => $host,
|
||||
'name' => Str::kebab('coolify' . $github_app->name)
|
||||
'name' => $name,
|
||||
'installation_url' => $installation_url,
|
||||
]);
|
||||
})->name('source.github.show');
|
||||
});
|
||||
|
52
routes/webhooks.php
Normal file
52
routes/webhooks.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
use App\Models\PrivateKey;
|
||||
use App\Models\GithubApp;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/source/github/redirect', function () {
|
||||
try {
|
||||
$code = request()->get('code');
|
||||
$state = request()->get('state');
|
||||
$github_app = GithubApp::where('uuid', $state)->firstOrFail();
|
||||
$api_url = data_get($github_app, 'api_url');
|
||||
$data = Http::withBody(null)->accept('application/vnd.github+json')->post("$api_url/app-manifests/$code/conversions")->throw()->json();
|
||||
$id = data_get($data, 'id');
|
||||
$slug = data_get($data, 'slug');
|
||||
$client_id = data_get($data, 'client_id');
|
||||
$client_secret = data_get($data, 'client_secret');
|
||||
$private_key = data_get($data, 'pem');
|
||||
$webhook_secret = data_get($data, 'webhook_secret');
|
||||
$private_key = PrivateKey::create([
|
||||
'name' => $slug,
|
||||
'private_key' => $private_key,
|
||||
'team_id' => $github_app->team_id
|
||||
]);
|
||||
$github_app->app_id = $id;
|
||||
$github_app->client_id = $client_id;
|
||||
$github_app->client_secret = $client_secret;
|
||||
$github_app->webhook_secret = $webhook_secret;
|
||||
$github_app->private_key_id = $private_key->id;
|
||||
$github_app->save();
|
||||
return redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
|
||||
} catch (\Exception $e) {
|
||||
return generalErrorHandler($e);
|
||||
}
|
||||
});
|
||||
|
||||
Route::get('/source/github/install', function () {
|
||||
try {
|
||||
$installation_id = request()->get('installation_id');
|
||||
$source = request()->get('source');
|
||||
$setup_action = request()->get('setup_action');
|
||||
$github_app = GithubApp::where('uuid', $source)->firstOrFail();
|
||||
if ($setup_action === 'install') {
|
||||
$github_app->installation_id = $installation_id;
|
||||
$github_app->save();
|
||||
}
|
||||
return redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
|
||||
} catch (\Exception $e) {
|
||||
return generalErrorHandler($e);
|
||||
}
|
||||
});
|
Loading…
Reference in New Issue
Block a user