From 5cd762c65d116c5908a2aeab28ac88637589f8ce Mon Sep 17 00:00:00 2001 From: Alireza Hassani Date: Sat, 8 Aug 2026 14:25:13 +0330 Subject: [PATCH] Accept HTTPS git repo URLs for storefront provision. Normalize https://git.meshkee.com/... to SSH for the websites VM deploy key while keeping the URL users paste. Co-authored-by: Cursor --- src/business-admin/business-admin.service.ts | 9 +++++---- src/business-admin/dto/add-domain.dto.ts | 8 ++++---- src/business-admin/dto/update-domain.dto.ts | 7 ++++--- src/website-deploy/website-deploy.util.ts | 21 +++++++++++++++++--- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/business-admin/business-admin.service.ts b/src/business-admin/business-admin.service.ts index 032ebca..4459c3e 100644 --- a/src/business-admin/business-admin.service.ts +++ b/src/business-admin/business-admin.service.ts @@ -41,6 +41,7 @@ import { WebsiteDeployAgentService } from '../website-deploy/website-deploy-agen import { deploySlugFromHost, isValidGitRepoUrl, + normalizeGitRepoUrlForClone, } from '../website-deploy/website-deploy.util'; type BusinessRow = { @@ -470,7 +471,7 @@ export class BusinessAdminService { if (gitRepoUrl && !isValidGitRepoUrl(gitRepoUrl)) { throw new BadRequestException( - 'gitRepoUrl must be an SSH git URL (e.g. git@git.meshkee.com:Meshkee-Websites/oaktasty.git)', + 'gitRepoUrl must be a git URL (e.g. https://git.meshkee.com/Meshkee-Websites/oaktasty.git)', ); } @@ -512,7 +513,7 @@ export class BusinessAdminService { await this.websiteDeployAgent.provision({ slug: deploySlug, host, - gitRepoUrl, + gitRepoUrl: normalizeGitRepoUrlForClone(gitRepoUrl), }); } catch (err) { if (err && typeof err === 'object' && 'message' in err && typeof err.message === 'string') { @@ -561,7 +562,7 @@ export class BusinessAdminService { if (gitRepoUrl && !isValidGitRepoUrl(gitRepoUrl)) { throw new BadRequestException( - 'gitRepoUrl must be an SSH git URL (e.g. git@git.meshkee.com:Meshkee-Websites/oaktasty.git)', + 'gitRepoUrl must be a git URL (e.g. https://git.meshkee.com/Meshkee-Websites/oaktasty.git)', ); } @@ -600,7 +601,7 @@ export class BusinessAdminService { await this.websiteDeployAgent.provision({ slug, host, - gitRepoUrl, + gitRepoUrl: normalizeGitRepoUrlForClone(gitRepoUrl), }); deploySlug = slug; nextGitRepoUrl = gitRepoUrl; diff --git a/src/business-admin/dto/add-domain.dto.ts b/src/business-admin/dto/add-domain.dto.ts index 6b4e1a9..34e5534 100644 --- a/src/business-admin/dto/add-domain.dto.ts +++ b/src/business-admin/dto/add-domain.dto.ts @@ -1,4 +1,5 @@ import { IsBoolean, IsOptional, IsString, Matches, MinLength } from 'class-validator'; +import { GIT_REPO_URL_RE } from '../../website-deploy/website-deploy.util'; export class AddDomainDto { @IsString() @@ -9,13 +10,12 @@ export class AddDomainDto { @IsBoolean() isPrimary?: boolean; - /** SSH git URL — when set, provisions storefront deploy on the websites VM. */ + /** HTTPS or SSH git URL — when set, provisions storefront deploy on the websites VM. */ @IsOptional() @IsString() - @Matches(/^(?:git@[\w.-]+:[\w./-]+\.git|ssh:\/\/git@[\w.-]+(?::\d+)?\/[\w./-]+\.git)$/i, { + @Matches(GIT_REPO_URL_RE, { message: - 'gitRepoUrl must be an SSH git URL (e.g. git@git.meshkee.com:Meshkee-Websites/oaktasty.git)', + 'gitRepoUrl must be a git URL (e.g. https://git.meshkee.com/Meshkee-Websites/oaktasty.git)', }) gitRepoUrl?: string; } - diff --git a/src/business-admin/dto/update-domain.dto.ts b/src/business-admin/dto/update-domain.dto.ts index e515b92..227080f 100644 --- a/src/business-admin/dto/update-domain.dto.ts +++ b/src/business-admin/dto/update-domain.dto.ts @@ -1,16 +1,17 @@ import { IsOptional, IsString, Matches, MinLength } from 'class-validator'; +import { GIT_REPO_URL_RE } from '../../website-deploy/website-deploy.util'; export class UpdateDomainDto { @IsString() @MinLength(1) host!: string; - /** SSH git URL — when set, provisions storefront deploy on the websites VM. */ + /** HTTPS or SSH git URL — when set, provisions storefront deploy on the websites VM. */ @IsOptional() @IsString() - @Matches(/^(?:git@[\w.-]+:[\w./-]+\.git|ssh:\/\/git@[\w.-]+(?::\d+)?\/[\w./-]+\.git)$/i, { + @Matches(GIT_REPO_URL_RE, { message: - 'gitRepoUrl must be an SSH git URL (e.g. git@git.meshkee.com:Meshkee-Websites/oaktasty.git)', + 'gitRepoUrl must be a git URL (e.g. https://git.meshkee.com/Meshkee-Websites/oaktasty.git)', }) gitRepoUrl?: string; } diff --git a/src/website-deploy/website-deploy.util.ts b/src/website-deploy/website-deploy.util.ts index f5d76d0..185998e 100644 --- a/src/website-deploy/website-deploy.util.ts +++ b/src/website-deploy/website-deploy.util.ts @@ -9,11 +9,26 @@ export function deploySlugFromHost(host: string): string { .replace(/^-|-$/g, ''); } -const GIT_SSH_RE = - /^(?:git@[\w.-]+:[\w./-]+\.git|ssh:\/\/git@[\w.-]+(?::\d+)?\/[\w./-]+\.git)$/i; +/** HTTPS or SSH git clone URLs (Meshkee Gitea and similar). */ +export const GIT_REPO_URL_RE = + /^(?:https?:\/\/[\w.-]+(?::\d+)?\/[\w./-]+\.git|git@[\w.-]+:[\w./-]+\.git|ssh:\/\/git@[\w.-]+(?::\d+)?\/[\w./-]+\.git)$/i; export function isValidGitRepoUrl(url: string): boolean { - return GIT_SSH_RE.test(url.trim()); + return GIT_REPO_URL_RE.test(url.trim()); +} + +/** + * Websites VM clones with an SSH deploy key — convert HTTPS Gitea URLs to SSH. + * https://git.meshkee.com/Meshkee-Websites/oaktasty.git + * → git@git.meshkee.com:Meshkee-Websites/oaktasty.git + */ +export function normalizeGitRepoUrlForClone(url: string): string { + const trimmed = url.trim().replace(/\/+$/, ''); + const https = trimmed.match(/^https?:\/\/([^/:]+)(?::\d+)?\/(.+\.git)$/i); + if (https) { + return `git@${https[1]}:${https[2]}`; + } + return trimmed; } /** Turn .../deploy into .../provision (or append /provision if bare). */