feat: automatically align Git repository origin host with configured server URL to prevent mismatches

This commit is contained in:
2026-03-08 11:28:00 +03:00
parent 603256eeaf
commit c7e9b5b6c5
6 changed files with 261 additions and 6 deletions

View File

@@ -22,7 +22,7 @@
let {
dashboardId,
envId = null,
currentBranch = 'main',
currentBranch = $bindable('main'),
} = $props();
// [/SECTION]

View File

@@ -19,7 +19,7 @@
// [/SECTION]
// [SECTION: PROPS]
let { dashboardId, envId = null, show = false, preferredTargetStage = "" } = $props();
let { dashboardId, envId = null, show = $bindable(false), preferredTargetStage = "" } = $props();
// [/SECTION]

View File

@@ -61,6 +61,8 @@
let isPushing = $state(false);
let autoPushAfterCommit = $state(true);
let repositoryProvider = $state('');
let repositoryBindingRemoteUrl = $state('');
let repositoryConfigUrl = $state('');
// [/SECTION]
const hasWorkspaceChanges = $derived.by(() => {
@@ -441,6 +443,24 @@
}
// [/DEF:resolvePushProviderLabel:Function]
// [DEF:extractHttpHost:Function]
/**
* @purpose Extract comparable host[:port] from URL string.
* @post Returns lowercase host token or empty string.
*/
function extractHttpHost(urlValue) {
const normalized = String(urlValue || '').trim();
if (!normalized) return '';
try {
const parsed = new URL(normalized);
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return '';
return String(parsed.host || '').toLowerCase();
} catch (_e) {
return '';
}
}
// [/DEF:extractHttpHost:Function]
// [DEF:buildSuggestedRepoName:Function]
/**
* @purpose Build deterministic repository name from dashboard title/id.
@@ -544,6 +564,18 @@
}
// [/DEF:handleBackdropClick:Function]
const originHost = $derived.by(() => extractHttpHost(repositoryBindingRemoteUrl));
const configHost = $derived.by(() => extractHttpHost(repositoryConfigUrl));
const hasOriginConfigMismatch = $derived.by(() => {
if (!originHost || !configHost) return false;
return originHost !== configHost;
});
$effect(() => {
const selectedConfig = getSelectedConfig() || resolveDefaultConfig(configs);
repositoryConfigUrl = selectedConfig?.url || '';
});
onMount(async () => {
try {
configs = await gitService.getConfigs();
@@ -559,9 +591,11 @@
try {
const binding = await gitService.getRepositoryBinding(dashboardId, envId);
repositoryProvider = binding?.provider || '';
repositoryBindingRemoteUrl = binding?.remote_url || '';
if (binding?.config_id) selectedConfigId = String(binding.config_id);
} catch (_e) {
repositoryProvider = '';
repositoryBindingRemoteUrl = '';
}
}
});
@@ -641,6 +675,15 @@
</div>
{:else}
<div class="space-y-4">
{#if hasOriginConfigMismatch}
<div class="rounded-lg border border-amber-300 bg-amber-50 p-3 text-sm text-amber-800">
<div class="font-semibold">Git server mismatch detected</div>
<div class="mt-1">
Configured server host: <code>{configHost}</code>, repository origin host: <code>{originHost}</code>.
Next push will auto-realign origin host to configured server.
</div>
</div>
{/if}
<div class="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-slate-200 bg-slate-50 px-3 py-2">
<div class="flex items-center gap-2">
<span class={`inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-semibold ${stageBadgeClass(currentEnvStage)}`}>

View File

@@ -15,8 +15,8 @@
let {
title = "",
class: className = "",
subtitle,
actions,
subtitle = null,
actions = null,
...rest
} = $props();
// [/SECTION: PROPS]