mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-12 15:53:46 -04:00
feat(gitea): support Forgejo and Codeberg in the Gitea App source
This commit is contained in:
@@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
- Save more than one named SMTP server on the transactional email and email notification pages, and switch between them
|
||||
- Give each SMTP server and Resend its own sender name and address, because each provider sends from its own verified domain
|
||||
- Disable a scheduled task automatically when it fails at least 5 times in a row and has had no successful run for 3 days. Coolify sends a notification on the scheduled task failure channels and shows the reason on the task page until you enable the task again
|
||||
- Connect Forgejo instances, including Codeberg and self-hosted Forgejo, with the Gitea / Forgejo App source. A new Provider list on the create form fills in the Gitea.com or Codeberg URLs, and webhooks also accept the `X-Forgejo-*` headers
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class Gitea extends Controller
|
||||
|
||||
// Only users who may administer the source can complete OAuth and store tokens.
|
||||
if (! $request->user()->can('update', $giteaApp)) {
|
||||
return redirect()->route('source.all')->with('error', 'You are not authorized to connect this Gitea App.');
|
||||
return redirect()->route('source.all')->with('error', 'You are not authorized to connect this Gitea / Forgejo App.');
|
||||
}
|
||||
|
||||
$baseUrl = rtrim($giteaApp->html_url, '/');
|
||||
@@ -85,7 +85,7 @@ class Gitea extends Controller
|
||||
{
|
||||
try {
|
||||
$return_payloads = collect([]);
|
||||
$x_gitea_event = Str::lower((string) $request->header('X-Gitea-Event'));
|
||||
$x_gitea_event = Str::lower((string) ($request->header('X-Gitea-Event') ?? $request->header('X-Forgejo-Event')));
|
||||
|
||||
if ($x_gitea_event === 'ping') {
|
||||
return response('pong');
|
||||
@@ -98,7 +98,7 @@ class Gitea extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
$signature = (string) $request->header('X-Gitea-Signature');
|
||||
$signature = (string) ($request->header('X-Gitea-Signature') ?? $request->header('X-Forgejo-Signature'));
|
||||
if ($signature === '') {
|
||||
$signature = Str::after((string) $request->header('X-Hub-Signature-256'), 'sha256=');
|
||||
}
|
||||
@@ -365,8 +365,8 @@ class Gitea extends Controller
|
||||
{
|
||||
try {
|
||||
$return_payloads = collect([]);
|
||||
$x_gitea_delivery = request()->header('X-Gitea-Delivery');
|
||||
$x_gitea_event = Str::lower((string) $request->header('X-Gitea-Event'));
|
||||
$x_gitea_delivery = $request->header('X-Gitea-Delivery') ?? $request->header('X-Forgejo-Delivery');
|
||||
$x_gitea_event = Str::lower((string) ($request->header('X-Gitea-Event') ?? $request->header('X-Forgejo-Event')));
|
||||
$x_hub_signature_256 = Str::after((string) $request->header('X-Hub-Signature-256'), 'sha256=');
|
||||
$content_type = $request->header('Content-Type');
|
||||
$payload = $request->collect();
|
||||
|
||||
@@ -185,8 +185,8 @@ class Select extends Component
|
||||
],
|
||||
[
|
||||
'id' => 'private-gitea-app',
|
||||
'name' => 'Git Repository (with Gitea App)',
|
||||
'description' => 'Deploy public or private Gitea repositories through a Gitea App, with automatic webhooks and pull request previews.',
|
||||
'name' => 'Git Repository (with Gitea / Forgejo App)',
|
||||
'description' => 'Deploy public or private Gitea, Forgejo, or Codeberg repositories through a Gitea / Forgejo App, with automatic webhooks and pull request previews.',
|
||||
'logo' => asset('svgs/gitea.svg'),
|
||||
],
|
||||
];
|
||||
|
||||
@@ -281,7 +281,7 @@ class Change extends Component
|
||||
|
||||
$this->syncData(true);
|
||||
$this->gitea_app->save();
|
||||
$this->dispatch('success', 'Gitea App updated.');
|
||||
$this->dispatch('success', 'Gitea / Forgejo App updated.');
|
||||
$this->dispatch('name-changed', uuid: $this->gitea_app->uuid, name: $this->gitea_app->name);
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
@@ -298,7 +298,7 @@ class Change extends Component
|
||||
|
||||
$this->gitea_app->is_system_wide = $this->isSystemWide;
|
||||
$this->gitea_app->save();
|
||||
$this->dispatch('success', 'Gitea App updated.');
|
||||
$this->dispatch('success', 'Gitea / Forgejo App updated.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
@@ -310,7 +310,7 @@ class Change extends Component
|
||||
$this->authorize('view', $this->gitea_app);
|
||||
|
||||
if (! $this->gitea_app->isConnected()) {
|
||||
$this->dispatch('error', 'Gitea App is not connected. Please complete the OAuth flow first.');
|
||||
$this->dispatch('error', 'Gitea / Forgejo App is not connected. Please complete the OAuth flow first.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -13,8 +13,16 @@ class Create extends Component
|
||||
{
|
||||
use AuthorizesRequests;
|
||||
|
||||
/** @var array<string, string> Hosted instances that the provider choice fills in. */
|
||||
public const HOSTED_PROVIDERS = [
|
||||
'gitea.com' => 'https://gitea.com',
|
||||
'codeberg.org' => 'https://codeberg.org',
|
||||
];
|
||||
|
||||
public string $name;
|
||||
|
||||
public string $provider = 'gitea.com';
|
||||
|
||||
public string $html_url = 'https://gitea.com';
|
||||
|
||||
public string $api_url = 'https://gitea.com/api/v1';
|
||||
@@ -34,6 +42,20 @@ class Create extends Component
|
||||
$this->name = substr(generate_random_name(), 0, 30);
|
||||
}
|
||||
|
||||
public function selectProvider(string $provider): void
|
||||
{
|
||||
$this->provider = $provider;
|
||||
|
||||
if (! isset(self::HOSTED_PROVIDERS[$provider])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->html_url = self::HOSTED_PROVIDERS[$provider];
|
||||
$this->api_url = $this->giteaApiUrlFromHtmlUrl($this->html_url);
|
||||
$this->custom_user = 'git';
|
||||
$this->custom_port = 22;
|
||||
}
|
||||
|
||||
public function updatingHtmlUrl(): void
|
||||
{
|
||||
$this->shouldDeriveApiUrlAfterHtmlUrlUpdate = blank($this->api_url)
|
||||
|
||||
@@ -133,6 +133,7 @@ if (! function_exists('auditLogWebhookFailure')) {
|
||||
'event_header' => $request?->header('X-GitHub-Event')
|
||||
?? $request?->header('X-Gitlab-Event')
|
||||
?? $request?->header('X-Gitea-Event')
|
||||
?? $request?->header('X-Forgejo-Event')
|
||||
?? $request?->header('X-Event-Key'),
|
||||
];
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ const GITEA_PAGE_SIZE = 50;
|
||||
function refreshGiteaToken(GiteaApp $source): void
|
||||
{
|
||||
if (! $source->refresh_token) {
|
||||
throw new RuntimeException('Gitea source has no refresh token. Please reconnect the Gitea app.');
|
||||
throw new RuntimeException('Gitea / Forgejo source has no refresh token. Please reconnect the Gitea / Forgejo App.');
|
||||
}
|
||||
|
||||
$safetyMargin = 60;
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
<section class="application-settings-section">
|
||||
<div class="application-settings-section-header">
|
||||
<div>
|
||||
<h2>Gitea App</h2>
|
||||
<p>Connect a Gitea App before selecting a private repository.</p>
|
||||
<h2>Gitea / Forgejo App</h2>
|
||||
<p>Connect a Gitea / Forgejo App before selecting a private repository.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="application-settings-section-body">
|
||||
<x-empty title="No Gitea Apps"
|
||||
<x-empty title="No Gitea / Forgejo Apps"
|
||||
description="Create an app to grant Coolify access to selected repositories."
|
||||
icon-name="sources">
|
||||
<x-slot:contents>
|
||||
<x-modal-input buttonTitle="+ Add Gitea App" title="New Gitea App" closeOutside="false">
|
||||
<x-modal-input buttonTitle="+ Add Gitea / Forgejo App" title="New Gitea / Forgejo App" closeOutside="false">
|
||||
<livewire:source.gitea.create />
|
||||
</x-modal-input>
|
||||
</x-slot:contents>
|
||||
@@ -23,10 +23,10 @@
|
||||
<section class="application-settings-section">
|
||||
<div class="application-settings-section-header">
|
||||
<div>
|
||||
<h2>Choose Gitea App</h2>
|
||||
<p>Select the Gitea App that can access the repository you want to deploy.</p>
|
||||
<h2>Choose Gitea / Forgejo App</h2>
|
||||
<p>Select the Gitea / Forgejo App that can access the repository you want to deploy.</p>
|
||||
</div>
|
||||
<x-modal-input buttonTitle="+ Add Gitea App" title="New Gitea App" closeOutside="false">
|
||||
<x-modal-input buttonTitle="+ Add Gitea / Forgejo App" title="New Gitea / Forgejo App" closeOutside="false">
|
||||
<livewire:source.gitea.create />
|
||||
</x-modal-input>
|
||||
</div>
|
||||
@@ -59,7 +59,7 @@
|
||||
<div class="application-settings-section-header">
|
||||
<div>
|
||||
<h2>Choose repository</h2>
|
||||
<p>Search repositories available through the selected Gitea App.</p>
|
||||
<p>Search repositories available through the selected Gitea / Forgejo App.</p>
|
||||
</div>
|
||||
@if ($gitea_app_id)
|
||||
<x-forms.button wire:click.prevent="loadRepositories({{ $gitea_app_id }})">
|
||||
@@ -85,7 +85,7 @@
|
||||
</div>
|
||||
@else
|
||||
<x-empty size="sm" title="No repositories available"
|
||||
description="Review this Gitea App configuration and grant access to a repository." />
|
||||
description="Review this Gitea / Forgejo App configuration and grant access to a repository." />
|
||||
@endif
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div>
|
||||
<x-slot:title>
|
||||
{{ $name ?: 'Gitea App' }} | Sources | Coolify
|
||||
{{ $name ?: 'Gitea / Forgejo App' }} | Sources | Coolify
|
||||
</x-slot>
|
||||
|
||||
@if ($isConnected)
|
||||
@@ -8,12 +8,12 @@
|
||||
<div class="min-w-0">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<h1 class="truncate text-[24px]! leading-7! font-semibold! tracking-tight!">
|
||||
{{ $name ?: 'Gitea App' }}
|
||||
{{ $name ?: 'Gitea / Forgejo App' }}
|
||||
</h1>
|
||||
<x-status-badge label="Connected" type="success" />
|
||||
</div>
|
||||
<p class="mt-1 text-[13px] text-neutral-500 dark:text-fg-dim">
|
||||
{{ filled($organization) ? 'Gitea App for '.$organization : 'Private Gitea source' }}
|
||||
{{ filled($organization) ? 'Gitea / Forgejo App for '.$organization : 'Private Gitea / Forgejo source' }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex shrink-0 flex-wrap items-center gap-2 sm:ml-auto">
|
||||
@@ -23,11 +23,11 @@
|
||||
</x-forms.button>
|
||||
@endcan
|
||||
@can('delete', $gitea_app)
|
||||
<x-modal-confirmation title="Confirm Gitea App Deletion?" isErrorButton buttonTitle="Delete"
|
||||
submitAction="delete" :actions="['The selected Gitea App will be permanently deleted.']"
|
||||
<x-modal-confirmation title="Confirm Gitea / Forgejo App Deletion?" isErrorButton buttonTitle="Delete"
|
||||
submitAction="delete" :actions="['The selected Gitea / Forgejo App will be permanently deleted.']"
|
||||
confirmationText="{{ data_get($gitea_app, 'name') }}"
|
||||
confirmationLabel="Please confirm by entering the Gitea App Name below"
|
||||
shortConfirmationLabel="Gitea App Name" :confirmWithPassword="false"
|
||||
confirmationLabel="Please confirm by entering the Gitea / Forgejo App Name below"
|
||||
shortConfirmationLabel="Gitea / Forgejo App Name" :confirmWithPassword="false"
|
||||
step2ButtonText="Permanently Delete" />
|
||||
@endcan
|
||||
</div>
|
||||
@@ -44,20 +44,20 @@
|
||||
@if (! isCloud())
|
||||
<div class="lg:col-span-2 max-w-xs">
|
||||
<x-forms.checkbox canGate="update" :canResource="$gitea_app" label="System wide"
|
||||
helper="If checked, this Gitea App will be available for everyone in this Coolify instance."
|
||||
helper="If checked, this Gitea / Forgejo App will be available for everyone in this Coolify instance."
|
||||
instantSave id="isSystemWide" />
|
||||
</div>
|
||||
@if ($isSystemWide)
|
||||
<div class="lg:col-span-2">
|
||||
<x-callout type="warning" title="Shared with every team">
|
||||
System-wide Gitea Apps are shared across all teams on this Coolify instance. Prefer team-specific apps when you need repository isolation.
|
||||
System-wide Gitea / Forgejo Apps are shared across all teams on this Coolify instance. Prefer team-specific apps when you need repository isolation.
|
||||
</x-callout>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
<x-application.settings-subsection title="Webhook"
|
||||
helper="Configure this webhook URL in Gitea (user, organization, or repository settings → Webhooks → Add webhook → Gitea).">
|
||||
helper="Configure this webhook URL in Gitea or Forgejo (user, organization, or repository settings → Webhooks → Add webhook → Gitea or Forgejo).">
|
||||
<div class="grid gap-4 lg:grid-cols-2">
|
||||
<div class="lg:col-span-2">
|
||||
<x-forms.input readonly label="Webhook URL"
|
||||
@@ -65,7 +65,7 @@
|
||||
</div>
|
||||
<x-forms.input canGate="update" :canResource="$gitea_app" id="webhookSecret"
|
||||
label="Webhook secret" type="password"
|
||||
helper="Set this as the Secret in a Gitea webhook (user, organization, or repository settings → Webhooks → Add webhook → Gitea), content type application/json, trigger on Push and Pull Request events. Stored encrypted." />
|
||||
helper="Set this as the Secret in a Gitea webhook (user, organization, or repository settings → Webhooks → Add webhook → Gitea or Forgejo), content type application/json, trigger on Push and Pull Request events. Stored encrypted." />
|
||||
</div>
|
||||
</x-application.settings-subsection>
|
||||
</x-application.settings-section>
|
||||
@@ -73,7 +73,7 @@
|
||||
<x-application.settings-section id="connection-section" title="Connection"
|
||||
helper="OAuth credentials and the endpoints Coolify uses to reach this source.">
|
||||
<x-application.settings-subsection first title="OAuth credentials"
|
||||
helper="Client credentials from your Gitea OAuth2 application.">
|
||||
helper="Client credentials from your Gitea or Forgejo OAuth2 application.">
|
||||
<div class="grid gap-4 lg:grid-cols-2">
|
||||
<x-forms.input canGate="update" :canResource="$gitea_app" id="clientId"
|
||||
label="Client ID" />
|
||||
@@ -85,10 +85,10 @@
|
||||
</div>
|
||||
</x-application.settings-subsection>
|
||||
<x-application.settings-subsection title="Self-hosted / advanced"
|
||||
helper="Override endpoints and SSH settings for self-hosted Gitea.">
|
||||
helper="Override endpoints and SSH settings for self-hosted Gitea or Forgejo.">
|
||||
<div class="grid gap-4 lg:grid-cols-2">
|
||||
<x-forms.input canGate="update" :canResource="$gitea_app" id="htmlUrl"
|
||||
label="Gitea URL" />
|
||||
label="Instance URL" />
|
||||
<x-forms.input canGate="update" :canResource="$gitea_app" id="apiUrl" label="API URL" />
|
||||
<x-forms.input canGate="update" :canResource="$gitea_app" id="customUser"
|
||||
label="SSH user" />
|
||||
@@ -110,10 +110,10 @@
|
||||
|
||||
<div x-data="{ search: '' }" class="application-settings-form mt-6">
|
||||
<x-application.settings-section title="Resources"
|
||||
description="Applications currently using this Gitea App." flush>
|
||||
description="Applications currently using this Gitea / Forgejo App." flush>
|
||||
@if ($applications->isEmpty())
|
||||
<x-empty title="No resources use this source"
|
||||
description="Applications will appear here after this Gitea App is selected as their source."
|
||||
description="Applications will appear here after this Gitea / Forgejo App is selected as their source."
|
||||
icon-name="sources" size="sm" />
|
||||
@else
|
||||
<div class="border-b border-neutral-200 p-3 dark:border-white/[0.08]">
|
||||
@@ -164,19 +164,19 @@
|
||||
<header class="mb-8 flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div class="min-w-0">
|
||||
<h1 class="truncate text-[24px]! leading-7! font-semibold! tracking-tight!">
|
||||
{{ $name ?: 'Gitea App' }}
|
||||
{{ $name ?: 'Gitea / Forgejo App' }}
|
||||
</h1>
|
||||
<p class="mt-1 text-[13px] text-neutral-500 dark:text-fg-dim">
|
||||
Finish connecting this Gitea App before using it as a source
|
||||
Finish connecting this Gitea / Forgejo App before using it as a source
|
||||
</p>
|
||||
</div>
|
||||
@can('delete', $gitea_app)
|
||||
<div class="shrink-0 sm:ml-auto">
|
||||
<x-modal-confirmation title="Confirm Gitea App Deletion?" isErrorButton buttonTitle="Delete"
|
||||
submitAction="delete" :actions="['The selected Gitea App will be permanently deleted.']"
|
||||
<x-modal-confirmation title="Confirm Gitea / Forgejo App Deletion?" isErrorButton buttonTitle="Delete"
|
||||
submitAction="delete" :actions="['The selected Gitea / Forgejo App will be permanently deleted.']"
|
||||
confirmationText="{{ data_get($gitea_app, 'name') }}"
|
||||
confirmationLabel="Please confirm by entering the Gitea App Name below"
|
||||
shortConfirmationLabel="Gitea App Name" :confirmWithPassword="false"
|
||||
confirmationLabel="Please confirm by entering the Gitea / Forgejo App Name below"
|
||||
shortConfirmationLabel="Gitea / Forgejo App Name" :confirmWithPassword="false"
|
||||
step2ButtonText="Permanently Delete" />
|
||||
</div>
|
||||
@endcan
|
||||
@@ -194,7 +194,7 @@
|
||||
}
|
||||
}">
|
||||
<x-application.settings-section title="Step 1 · Create an OAuth application"
|
||||
description="In Gitea, open Manage OAuth2 Applications and create a new application with the redirect URI below.">
|
||||
description="In Gitea or Forgejo, open Settings → Applications → Manage OAuth2 Applications and create a new application with the redirect URI below.">
|
||||
<div class="flex flex-col gap-3 text-[12px] leading-5 text-neutral-600 dark:text-fg-dim">
|
||||
<a href="{{ rtrim($htmlUrl, '/') }}/user/settings/applications" target="_blank"
|
||||
class="inline-flex w-fit items-center gap-1 font-medium text-black underline-offset-2 hover:underline dark:text-fg">
|
||||
@@ -216,7 +216,7 @@
|
||||
|
||||
<form wire:submit="submit" class="contents">
|
||||
<x-application.settings-section title="Step 2 · Enter credentials"
|
||||
description="Paste the Client ID and Client secret from Gitea, then save.">
|
||||
description="Paste the Client ID and Client secret from Gitea or Forgejo, then save.">
|
||||
<x-slot:actions>
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
</x-slot:actions>
|
||||
@@ -224,10 +224,10 @@
|
||||
<div class="grid gap-4 lg:grid-cols-2">
|
||||
<x-forms.input id="name" label="Name" />
|
||||
<x-forms.input id="clientId" label="Client ID" required
|
||||
helper="The Client ID from your Gitea OAuth2 application." />
|
||||
helper="The Client ID from your Gitea or Forgejo OAuth2 application." />
|
||||
<x-forms.input id="clientSecretInput" label="Client secret" type="password"
|
||||
:required="blank($clientSecretInput) && blank(data_get($gitea_app, 'client_secret'))"
|
||||
helper="The Client secret from your Gitea OAuth2 application. Saved encrypted." />
|
||||
helper="The Client secret from your Gitea or Forgejo OAuth2 application. Saved encrypted." />
|
||||
<x-forms.input id="organization" label="Organization"
|
||||
helper="Optional. Comma-separated organization or user names to filter repositories." />
|
||||
</div>
|
||||
@@ -235,7 +235,7 @@
|
||||
@if (! isCloud() || isDev())
|
||||
<div class="mt-4 grid gap-4 lg:grid-cols-2">
|
||||
<div class="lg:col-span-2 text-[12px] text-neutral-500 dark:text-fg-dim">
|
||||
Gitea will redirect back to this Coolify URL. It must match the Redirect URI on your Gitea OAuth2 application exactly.
|
||||
Gitea or Forgejo will redirect back to this Coolify URL. It must match the Redirect URI on your Gitea or Forgejo OAuth2 application exactly.
|
||||
</div>
|
||||
<div class="lg:col-span-2 max-w-md">
|
||||
<x-forms.listbox id="use_custom_webhook_endpoint" label="Webhook endpoint"
|
||||
@@ -249,7 +249,7 @@
|
||||
<div class="lg:col-span-2" x-show="!useCustomWebhookEndpoint">
|
||||
<x-forms.listbox id="webhook_endpoint" x-model="webhookEndpoint"
|
||||
label="Selected endpoint"
|
||||
helper="Gitea will use this endpoint unless custom mode is enabled."
|
||||
helper="Gitea or Forgejo will use this endpoint unless custom mode is enabled."
|
||||
:options="collect([$fqdn, $ipv4, $ipv6, config('app.url')])
|
||||
->filter()->unique()->map(fn ($endpoint) => [
|
||||
'value' => $endpoint,
|
||||
@@ -260,7 +260,7 @@
|
||||
<x-forms.input x-model="customWebhookEndpoint" id="custom_webhook_endpoint"
|
||||
type="url" label="Custom endpoint"
|
||||
placeholder="https://coolify.example.com"
|
||||
helper="Gitea will use this custom public URL. Do not include /webhooks." />
|
||||
helper="Gitea or Forgejo will use this custom public URL. Do not include /webhooks." />
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@@ -276,16 +276,16 @@
|
||||
</button>
|
||||
<div x-cloak x-show="open" x-collapse.duration.200ms
|
||||
class="mt-3 grid gap-4 rounded-lg border border-neutral-200 p-3 lg:grid-cols-2 dark:border-white/[0.08]">
|
||||
<x-forms.input id="htmlUrl" label="Gitea URL"
|
||||
helper="Only change this for self-hosted Gitea (e.g. https://gitea.example.com)." />
|
||||
<x-forms.input id="htmlUrl" label="Instance URL"
|
||||
helper="Only change this for self-hosted Gitea or Forgejo (e.g. https://git.example.com)." />
|
||||
<x-forms.input id="apiUrl" label="API URL"
|
||||
helper="Usually your Gitea URL with /api/v1 appended." />
|
||||
helper="Usually your instance URL with /api/v1 appended." />
|
||||
<x-forms.input id="customUser" label="SSH user" />
|
||||
<x-forms.input type="number" id="customPort" label="SSH port" />
|
||||
@if (! isCloud())
|
||||
<div class="max-w-xs lg:col-span-2">
|
||||
<x-forms.checkbox label="System wide" id="isSystemWide"
|
||||
helper="If checked, this Gitea App will be available for everyone in this Coolify instance." />
|
||||
helper="If checked, this Gitea / Forgejo App will be available for everyone in this Coolify instance." />
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@@ -294,11 +294,11 @@
|
||||
</form>
|
||||
|
||||
@if ($clientId)
|
||||
<x-application.settings-section title="Step 3 · Authorize with Gitea"
|
||||
description="Authorize Coolify with your Gitea instance. The redirect URI must match the one configured in Gitea.">
|
||||
<x-application.settings-section title="Step 3 · Authorize with Gitea or Forgejo"
|
||||
description="Authorize Coolify with your Gitea or Forgejo instance. The redirect URI must match the one configured there.">
|
||||
<a href="{{ $this->getOAuthUrl() }}" wire:key="oauth-url-{{ md5((string) $redirectUri) }}"
|
||||
class="button button-highlighted">
|
||||
Connect to Gitea
|
||||
Connect to Gitea / Forgejo
|
||||
<x-external-link />
|
||||
</a>
|
||||
</x-application.settings-section>
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
@can('create', \App\Models\GiteaApp::class)
|
||||
<form wire:submit="createGiteaApp" class="flex w-full flex-col gap-4">
|
||||
<p class="text-[12px] leading-5 text-neutral-500 dark:text-fg-dim">
|
||||
Connect a Gitea OAuth2 application for private repositories, webhooks, and deployments.
|
||||
Connect a Gitea or Forgejo OAuth2 application (Gitea.com, Codeberg, or your own instance) for private repositories, webhooks, and deployments.
|
||||
</p>
|
||||
|
||||
<x-forms.listbox id="provider" label="Provider" onChange="selectProvider" :onChangeArgs="[]"
|
||||
:options="[
|
||||
['value' => 'gitea.com', 'label' => 'Gitea.com'],
|
||||
['value' => 'codeberg.org', 'label' => 'Codeberg (Forgejo)'],
|
||||
['value' => 'self-hosted', 'label' => 'Self-hosted Gitea or Forgejo'],
|
||||
]"
|
||||
helper="Codeberg runs Forgejo. For your own Gitea or Forgejo instance, select Self-hosted and enter its URL below." />
|
||||
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
<x-forms.input id="name" label="Name" required />
|
||||
<x-forms.input id="organization" label="Organization"
|
||||
@@ -15,11 +23,11 @@
|
||||
<div x-data="{ showWarning: @entangle('is_system_wide') }">
|
||||
<div class="max-w-xs">
|
||||
<x-forms.checkbox id="is_system_wide" label="System wide"
|
||||
helper="If checked, this Gitea App will be available for everyone in this Coolify instance." />
|
||||
helper="If checked, this Gitea / Forgejo App will be available for everyone in this Coolify instance." />
|
||||
</div>
|
||||
<div x-cloak x-show="showWarning" x-transition class="mt-3">
|
||||
<x-callout type="warning" title="Shared with every team">
|
||||
System-wide Gitea Apps are available to every team on this instance. Prefer team-specific apps when you need repository isolation.
|
||||
System-wide Gitea / Forgejo Apps are available to every team on this instance. Prefer team-specific apps when you need repository isolation.
|
||||
</x-callout>
|
||||
</div>
|
||||
</div>
|
||||
@@ -27,10 +35,10 @@
|
||||
|
||||
<div x-data="{
|
||||
open: false,
|
||||
}" class="rounded-lg border border-neutral-200 dark:border-white/[0.08]">
|
||||
}" x-effect="if ($wire.provider === 'self-hosted') open = true" class="rounded-lg border border-neutral-200 dark:border-white/[0.08]">
|
||||
<button type="button" @click="open = !open"
|
||||
class="flex w-full items-center justify-between px-3 py-2.5 text-left text-[12px] font-medium text-neutral-700 transition-colors hover:bg-neutral-50 dark:text-fg-dim dark:hover:bg-white/[0.03]">
|
||||
Self-hosted Gitea
|
||||
Self-hosted Gitea or Forgejo
|
||||
<svg class="size-3.5 transition-transform" :class="{ 'rotate-180': open }" viewBox="0 0 24 24"
|
||||
fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
@@ -38,10 +46,10 @@
|
||||
</button>
|
||||
<div x-cloak x-show="open" x-collapse.duration.200ms class="border-t border-neutral-200 px-3 py-3 dark:border-white/[0.08]">
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
<x-forms.input id="html_url" label="Gitea URL" required
|
||||
helper="For self-hosted Gitea, enter your instance URL (e.g. https://gitea.example.com)." />
|
||||
<x-forms.input id="html_url" label="Instance URL" required
|
||||
helper="For self-hosted Gitea or Forgejo, enter your instance URL (e.g. https://git.example.com)." />
|
||||
<x-forms.input id="api_url" label="API URL" required
|
||||
helper="Usually your Gitea URL with /api/v1 appended." />
|
||||
helper="Usually your instance URL with /api/v1 appended." />
|
||||
<x-forms.input id="custom_user" label="Custom Git user" required />
|
||||
<x-forms.input id="custom_port" type="number" label="Custom Git port" required />
|
||||
</div>
|
||||
@@ -54,6 +62,6 @@
|
||||
</form>
|
||||
@else
|
||||
<x-callout type="danger" title="Insufficient permissions">
|
||||
You don't have permission to create new Gitea Apps. Contact your team administrator.
|
||||
You don't have permission to create new Gitea / Forgejo Apps. Contact your team administrator.
|
||||
</x-callout>
|
||||
@endcan
|
||||
|
||||
@@ -44,12 +44,12 @@
|
||||
</x-slot:content>
|
||||
<livewire:source.gitlab.create />
|
||||
</x-modal-input>
|
||||
<x-modal-input title="New Gitea App" :closeOutside="false">
|
||||
<x-modal-input title="New Gitea / Forgejo App" :closeOutside="false">
|
||||
<x-slot:content>
|
||||
<button type="button" @click="dropdownOpen = false"
|
||||
class="listbox-option justify-start! gap-2.5!" role="menuitem">
|
||||
<x-git-icon class="size-3.5 shrink-0 opacity-70" git="App\Models\GiteaApp" />
|
||||
Gitea App
|
||||
Gitea / Forgejo App
|
||||
</button>
|
||||
</x-slot:content>
|
||||
<livewire:source.gitea.create />
|
||||
@@ -71,7 +71,7 @@
|
||||
'name' => $source->name,
|
||||
'provider' => match ($source->getMorphClass()) {
|
||||
'App\\Models\\GithubApp' => 'GitHub',
|
||||
'App\\Models\\GiteaApp' => 'Gitea',
|
||||
'App\\Models\\GiteaApp' => 'Gitea / Forgejo',
|
||||
default => 'GitLab',
|
||||
},
|
||||
'organization' => $isGitlab ? $source->group_name : $source->organization,
|
||||
@@ -143,7 +143,7 @@
|
||||
</div>
|
||||
</a>
|
||||
@elseif ($source->getMorphClass() === 'App\Models\GiteaApp')
|
||||
<a x-show="matches(@js([$source->name, 'Gitea', $source->organization, $source->isConnected() ? 'Connected' : 'Setup incomplete']))" class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
|
||||
<a x-show="matches(@js([$source->name, 'Gitea', 'Forgejo', $source->organization, $source->isConnected() ? 'Connected' : 'Setup incomplete']))" class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
|
||||
{{ wireNavigate() }}
|
||||
href="{{ route('source.gitea.show', ['gitea_app_uuid' => data_get($source, 'uuid')]) }}">
|
||||
<div class="flex items-start gap-3">
|
||||
|
||||
@@ -48,7 +48,7 @@ describe('Gitea source setup view', function () {
|
||||
test('shows incomplete-setup guidance with the credential form', function () {
|
||||
Livewire::withQueryParams(['gitea_app_uuid' => $this->giteaApp->uuid])
|
||||
->test(Change::class)
|
||||
->assertSee('Finish connecting this Gitea App before using it as a source')
|
||||
->assertSee('Finish connecting this Gitea / Forgejo App before using it as a source')
|
||||
->assertSee('https://gitea.com/user/settings/applications')
|
||||
->assertSee('Client ID')
|
||||
->assertSee('Client secret')
|
||||
|
||||
@@ -36,7 +36,7 @@ test('sources page lists gitea apps with a link to their settings', function ()
|
||||
|
||||
$this->get(route('source.all'))
|
||||
->assertOk()
|
||||
->assertSee('New Gitea App')
|
||||
->assertSee('New Gitea / Forgejo App')
|
||||
->assertSee('Team Gitea')
|
||||
->assertSee('Gitea · acme')
|
||||
->assertSee(route('source.gitea.show', ['gitea_app_uuid' => $this->giteaApp->uuid]), false);
|
||||
|
||||
Reference in New Issue
Block a user