feat: custom port for git instances

This commit is contained in:
Andras Bacsai
2022-07-12 11:01:48 +02:00
parent 9b47de71fc
commit 5a7edcb762
8 changed files with 137 additions and 29 deletions

View File

@@ -0,0 +1,24 @@
-- RedefineTables
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_GitSource" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"type" TEXT,
"apiUrl" TEXT,
"htmlUrl" TEXT,
"customPort" INTEGER NOT NULL DEFAULT 22,
"organization" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
"githubAppId" TEXT,
"gitlabAppId" TEXT,
CONSTRAINT "GitSource_githubAppId_fkey" FOREIGN KEY ("githubAppId") REFERENCES "GithubApp" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "GitSource_gitlabAppId_fkey" FOREIGN KEY ("gitlabAppId") REFERENCES "GitlabApp" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
INSERT INTO "new_GitSource" ("apiUrl", "createdAt", "githubAppId", "gitlabAppId", "htmlUrl", "id", "name", "organization", "type", "updatedAt") SELECT "apiUrl", "createdAt", "githubAppId", "gitlabAppId", "htmlUrl", "id", "name", "organization", "type", "updatedAt" FROM "GitSource";
DROP TABLE "GitSource";
ALTER TABLE "new_GitSource" RENAME TO "GitSource";
CREATE UNIQUE INDEX "GitSource_githubAppId_key" ON "GitSource"("githubAppId");
CREATE UNIQUE INDEX "GitSource_gitlabAppId_key" ON "GitSource"("gitlabAppId");
PRAGMA foreign_key_check;
PRAGMA foreign_keys=ON;

View File

@@ -218,6 +218,7 @@ model GitSource {
type String? type String?
apiUrl String? apiUrl String?
htmlUrl String? htmlUrl String?
customPort Int @default(22)
organization String? organization String?
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt

View File

@@ -56,7 +56,7 @@ import * as buildpacks from '../lib/buildPacks';
exposePort, exposePort,
baseImage, baseImage,
baseBuildImage, baseBuildImage,
deploymentType deploymentType,
} = message } = message
let { let {
branch, branch,
@@ -127,6 +127,7 @@ import * as buildpacks from '../lib/buildPacks';
repodir, repodir,
githubAppId: gitSource.githubApp?.id, githubAppId: gitSource.githubApp?.id,
gitlabAppId: gitSource.gitlabApp?.id, gitlabAppId: gitSource.gitlabApp?.id,
customPort: gitSource.customPort,
repository, repository,
branch, branch,
buildId, buildId,

View File

@@ -11,7 +11,8 @@ export default async function ({
apiUrl, apiUrl,
htmlUrl, htmlUrl,
branch, branch,
buildId buildId,
customPort
}: { }: {
applicationId: string; applicationId: string;
workdir: string; workdir: string;
@@ -21,6 +22,7 @@ export default async function ({
htmlUrl: string; htmlUrl: string;
branch: string; branch: string;
buildId: string; buildId: string;
customPort: number;
}): Promise<string> { }): Promise<string> {
const { default: got } = await import('got') const { default: got } = await import('got')
const url = htmlUrl.replace('https://', '').replace('http://', ''); const url = htmlUrl.replace('https://', '').replace('http://', '');
@@ -54,7 +56,7 @@ export default async function ({
applicationId applicationId
}); });
await asyncExecShell( await asyncExecShell(
`git clone -q -b ${branch} https://x-access-token:${token}@${url}/${repository}.git ${workdir}/ && cd ${workdir} && git submodule update --init --recursive && git lfs pull && cd .. ` `git clone -q -b ${branch} https://x-access-token:${token}@${url}/${repository}.git --config core.sshCommand="ssh -p ${customPort}" ${workdir}/ && cd ${workdir} && git submodule update --init --recursive && git lfs pull && cd .. `
); );
const { stdout: commit } = await asyncExecShell(`cd ${workdir}/ && git rev-parse HEAD`); const { stdout: commit } = await asyncExecShell(`cd ${workdir}/ && git rev-parse HEAD`);
return commit.replace('\n', ''); return commit.replace('\n', '');

View File

@@ -9,7 +9,8 @@ export default async function ({
repository, repository,
branch, branch,
buildId, buildId,
privateSshKey privateSshKey,
customPort
}: { }: {
applicationId: string; applicationId: string;
workdir: string; workdir: string;
@@ -19,6 +20,7 @@ export default async function ({
buildId: string; buildId: string;
repodir: string; repodir: string;
privateSshKey: string; privateSshKey: string;
customPort: number;
}): Promise<string> { }): Promise<string> {
const url = htmlUrl.replace('https://', '').replace('http://', '').replace(/\/$/, ''); const url = htmlUrl.replace('https://', '').replace('http://', '').replace(/\/$/, '');
await saveBuildLog({ line: 'GitLab importer started.', buildId, applicationId }); await saveBuildLog({ line: 'GitLab importer started.', buildId, applicationId });
@@ -32,7 +34,7 @@ export default async function ({
}); });
await asyncExecShell( await asyncExecShell(
`git clone -q -b ${branch} git@${url}:${repository}.git --config core.sshCommand="ssh -q -i ${repodir}id.rsa -o StrictHostKeyChecking=no" ${workdir}/ && cd ${workdir}/ && git submodule update --init --recursive && git lfs pull && cd .. ` `git clone -q -b ${branch} git@${url}:${repository}.git --config core.sshCommand="ssh -p ${customPort} -q -i ${repodir}id.rsa -o StrictHostKeyChecking=no" ${workdir}/ && cd ${workdir}/ && git submodule update --init --recursive && git lfs pull && cd .. `
); );
const { stdout: commit } = await asyncExecShell(`cd ${workdir}/ && git rev-parse HEAD`); const { stdout: commit } = await asyncExecShell(`cd ${workdir}/ && git rev-parse HEAD`);
return commit.replace('\n', ''); return commit.replace('\n', '');

View File

@@ -20,10 +20,11 @@ export async function listSources(request: FastifyRequest) {
export async function saveSource(request, reply) { export async function saveSource(request, reply) {
try { try {
const { id } = request.params const { id } = request.params
const { name, htmlUrl, apiUrl } = request.body let { name, htmlUrl, apiUrl, customPort } = request.body
if (customPort) customPort = Number(customPort)
await prisma.gitSource.update({ await prisma.gitSource.update({
where: { id }, where: { id },
data: { name, htmlUrl, apiUrl } data: { name, htmlUrl, apiUrl, customPort }
}); });
return reply.code(201).send() return reply.code(201).send()
} catch ({ status, message }) { } catch ({ status, message }) {
@@ -45,7 +46,8 @@ export async function getSource(request: FastifyRequest) {
type: null, type: null,
htmlUrl: null, htmlUrl: null,
apiUrl: null, apiUrl: null,
organization: null organization: null,
customPort: 22,
}, },
settings settings
} }
@@ -58,7 +60,7 @@ export async function getSource(request: FastifyRequest) {
if (!source) { if (!source) {
throw { status: 404, message: 'Source not found.' } throw { status: 404, message: 'Source not found.' }
} }
if (source?.githubApp?.clientSecret) if (source?.githubApp?.clientSecret)
source.githubApp.clientSecret = decrypt(source.githubApp.clientSecret); source.githubApp.clientSecret = decrypt(source.githubApp.clientSecret);
if (source?.githubApp?.webhookSecret) if (source?.githubApp?.webhookSecret)
@@ -97,9 +99,12 @@ export async function deleteSource(request) {
} }
export async function saveGitHubSource(request: FastifyRequest, reply: FastifyReply) { export async function saveGitHubSource(request: FastifyRequest, reply: FastifyReply) {
try { try {
const { id } = request.params
const { name, type, htmlUrl, apiUrl, organization } = request.body
const { teamId } = request.user const { teamId } = request.user
const { id } = request.params
let { name, type, htmlUrl, apiUrl, organization, customPort } = request.body
if (customPort) customPort = Number(customPort)
if (id === 'new') { if (id === 'new') {
const newId = cuid() const newId = cuid()
await prisma.gitSource.create({ await prisma.gitSource.create({
@@ -109,6 +114,7 @@ export async function saveGitHubSource(request: FastifyRequest, reply: FastifyRe
htmlUrl, htmlUrl,
apiUrl, apiUrl,
organization, organization,
customPort,
type: 'github', type: 'github',
teams: { connect: { id: teamId } } teams: { connect: { id: teamId } }
} }
@@ -126,15 +132,16 @@ export async function saveGitLabSource(request: FastifyRequest, reply: FastifyRe
try { try {
const { id } = request.params const { id } = request.params
const { teamId } = request.user const { teamId } = request.user
let { type, name, htmlUrl, apiUrl, oauthId, appId, appSecret, groupName } = let { type, name, htmlUrl, apiUrl, oauthId, appId, appSecret, groupName, customPort } =
request.body request.body
oauthId = Number(oauthId); if (oauthId) oauthId = Number(oauthId);
if (customPort) customPort = Number(customPort)
const encryptedAppSecret = encrypt(appSecret); const encryptedAppSecret = encrypt(appSecret);
if (id === 'new') { if (id === 'new') {
const newId = cuid() const newId = cuid()
await prisma.gitSource.create({ data: { id: newId, type, apiUrl, htmlUrl, name, teams: { connect: { id: teamId } } } }); await prisma.gitSource.create({ data: { id: newId, type, apiUrl, htmlUrl, name, customPort, teams: { connect: { id: teamId } } } });
await prisma.gitlabApp.create({ await prisma.gitlabApp.create({
data: { data: {
teams: { connect: { id: teamId } }, teams: { connect: { id: teamId } },
@@ -150,7 +157,7 @@ export async function saveGitLabSource(request: FastifyRequest, reply: FastifyRe
id: newId id: newId
} }
} else { } else {
await prisma.gitSource.update({ where: { id }, data: { type, apiUrl, htmlUrl, name } }); await prisma.gitSource.update({ where: { id }, data: { type, apiUrl, htmlUrl, name, customPort } });
await prisma.gitlabApp.update({ await prisma.gitlabApp.update({
where: { id }, where: { id },
data: { data: {

View File

@@ -11,7 +11,11 @@
import { dev } from '$app/env'; import { dev } from '$app/env';
const { id } = $page.params; const { id } = $page.params;
$: selfHosted = source.htmlUrl !== 'https://github.com';
let loading = false; let loading = false;
async function handleSubmit() { async function handleSubmit() {
loading = true; loading = true;
try { try {
@@ -57,7 +61,8 @@
name: source.name, name: source.name,
htmlUrl: source.htmlUrl.replace(/\/$/, ''), htmlUrl: source.htmlUrl.replace(/\/$/, ''),
apiUrl: source.apiUrl.replace(/\/$/, ''), apiUrl: source.apiUrl.replace(/\/$/, ''),
organization: source.organization organization: source.organization,
customPort: source.customPort
}); });
const { organization, htmlUrl } = source; const { organization, htmlUrl } = source;
const { fqdn } = settings; const { fqdn } = settings;
@@ -113,8 +118,11 @@
<div class="mx-auto max-w-4xl px-6"> <div class="mx-auto max-w-4xl px-6">
{#if !source.githubAppId} {#if !source.githubAppId}
<form on:submit|preventDefault={newGithubApp} class="py-4"> <form on:submit|preventDefault={newGithubApp} class="py-4">
<div class="flex space-x-1 pb-5 font-bold"> <div class="flex space-x-1 pb-7 font-bold">
<div class="title">General</div> <div class="title">General</div>
{#if !source.githubAppId}
<button class="bg-orange-600" type="submit">Save</button>
{/if}
</div> </div>
<div class="grid grid-flow-row gap-2 px-10"> <div class="grid grid-flow-row gap-2 px-10">
<div class="grid grid-flow-row gap-2"> <div class="grid grid-flow-row gap-2">
@@ -131,6 +139,20 @@
<label for="apiUrl" class="text-base font-bold text-stone-100">API URL</label> <label for="apiUrl" class="text-base font-bold text-stone-100">API URL</label>
<input name="apiUrl" id="apiUrl" required bind:value={source.apiUrl} /> <input name="apiUrl" id="apiUrl" required bind:value={source.apiUrl} />
</div> </div>
<div class="grid grid-cols-2 items-center">
<label for="customPort" class="text-base font-bold text-stone-100">Custom SSH Port</label>
<input
name="customPort"
id="customPort"
disabled={!selfHosted || source.githubAppId}
readonly={!selfHosted || source.githubAppId}
required
value={source.customPort}
/>
<Explainer
text="If you use a self-hosted version of Git, you can provide custom port for all the Git related actions."
/>
</div>
<div class="grid grid-cols-2"> <div class="grid grid-cols-2">
<div class="flex flex-col"> <div class="flex flex-col">
<label for="organization" class="pt-2 text-base font-bold text-stone-100" <label for="organization" class="pt-2 text-base font-bold text-stone-100"
@@ -148,11 +170,6 @@
/> />
</div> </div>
</div> </div>
{#if source.apiUrl && source.htmlUrl && source.name}
<div class="text-center">
<button class=" mt-8 bg-orange-600" type="submit">Create new GitHub App</button>
</div>
{/if}
</form> </form>
{:else if source.githubApp?.installationId} {:else if source.githubApp?.installationId}
<form on:submit|preventDefault={handleSubmit} class="py-4"> <form on:submit|preventDefault={handleSubmit} class="py-4">
@@ -181,11 +198,39 @@
</div> </div>
<div class="grid grid-cols-2 items-center"> <div class="grid grid-cols-2 items-center">
<label for="htmlUrl" class="text-base font-bold text-stone-100">HTML URL</label> <label for="htmlUrl" class="text-base font-bold text-stone-100">HTML URL</label>
<input name="htmlUrl" id="htmlUrl" required bind:value={source.htmlUrl} /> <input
name="htmlUrl"
id="htmlUrl"
disabled={source.githubAppId}
readonly={source.githubAppId}
required
bind:value={source.htmlUrl}
/>
</div> </div>
<div class="grid grid-cols-2 items-center"> <div class="grid grid-cols-2 items-center">
<label for="apiUrl" class="text-base font-bold text-stone-100">API URL</label> <label for="apiUrl" class="text-base font-bold text-stone-100">API URL</label>
<input name="apiUrl" id="apiUrl" required bind:value={source.apiUrl} /> <input
name="apiUrl"
id="apiUrl"
required
disabled={source.githubAppId}
readonly={source.githubAppId}
bind:value={source.apiUrl}
/>
</div>
<div class="grid grid-cols-2 items-center">
<label for="customPort" class="text-base font-bold text-stone-100">Custom SSH Port</label>
<input
name="customPort"
id="customPort"
disabled={!selfHosted}
readonly={!selfHosted}
required
value={source.customPort}
/>
<Explainer
text="If you use a self-hosted version of Git, you can provide custom port for all the Git related actions."
/>
</div> </div>
<div class="grid grid-cols-2"> <div class="grid grid-cols-2">
<div class="flex flex-col"> <div class="flex flex-col">
@@ -207,7 +252,9 @@
{:else} {:else}
<div class="text-center"> <div class="text-center">
<a href={`${source.htmlUrl}/apps/${source.githubApp.name}/installations/new`}> <a href={`${source.htmlUrl}/apps/${source.githubApp.name}/installations/new`}>
<button class=" bg-orange-600 hover:bg-orange-500 mt-8">Install Repositories</button></a <button class="box-selection bg-orange-600 hover:bg-orange-500 text-xl"
>Install Repositories</button
></a
> >
</div> </div>
{/if} {/if}

View File

@@ -12,8 +12,8 @@
import { t } from '$lib/translations'; import { t } from '$lib/translations';
import { errorNotification } from '$lib/common'; import { errorNotification } from '$lib/common';
import { appSession } from '$lib/store'; import { appSession } from '$lib/store';
import { goto } from '$app/navigation';
const { id } = $page.params; const { id } = $page.params;
let url = settings.fqdn ? settings.fqdn : window.location.origin; let url = settings.fqdn ? settings.fqdn : window.location.origin;
if (dev) { if (dev) {
@@ -31,6 +31,8 @@
appSecret: null appSecret: null
}; };
} }
$: selfHosted = source.htmlUrl !== 'https://gitlab.com' ;
onMount(() => { onMount(() => {
oauthIdEl && oauthIdEl.focus(); oauthIdEl && oauthIdEl.focus();
}); });
@@ -49,7 +51,8 @@
oauthId: source.gitlabApp.oauthId, oauthId: source.gitlabApp.oauthId,
appId: source.gitlabApp.appId, appId: source.gitlabApp.appId,
appSecret: source.gitlabApp.appSecret, appSecret: source.gitlabApp.appSecret,
groupName: source.gitlabApp.groupName groupName: source.gitlabApp.groupName,
customPort: source.customPort
}); });
const from = $page.url.searchParams.get('from'); const from = $page.url.searchParams.get('from');
if (from) { if (from) {
@@ -67,7 +70,8 @@
await post(`/sources/${id}`, { await post(`/sources/${id}`, {
name: source.name, name: source.name,
htmlUrl: source.htmlUrl.replace(/\/$/, ''), htmlUrl: source.htmlUrl.replace(/\/$/, ''),
apiUrl: source.apiUrl.replace(/\/$/, '') apiUrl: source.apiUrl.replace(/\/$/, ''),
customPort: source.customPort
}); });
toast.push('Configuration saved.'); toast.push('Configuration saved.');
} catch (error) { } catch (error) {
@@ -119,6 +123,10 @@
window.open(`${source.htmlUrl}/-/profile/applications`); window.open(`${source.htmlUrl}/-/profile/applications`);
break; break;
case 'group': case 'group':
if (!source.gitlabApp.groupName) {
toast.push('Please enter a group name first.');
return;
}
window.open( window.open(
`${source.htmlUrl}/groups/${source.gitlabApp.groupName}/-/settings/applications` `${source.htmlUrl}/groups/${source.gitlabApp.groupName}/-/settings/applications`
); );
@@ -146,6 +154,8 @@
<button on:click|preventDefault={changeSettings} <button on:click|preventDefault={changeSettings}
>{$t('source.change_app_settings', { name: 'GitLab' })}</button >{$t('source.change_app_settings', { name: 'GitLab' })}</button
> >
{:else}
<button on:click|preventDefault|stopPropagation={newApp}>Create new GitLab App</button>
{/if} {/if}
{/if} {/if}
</div> </div>
@@ -204,7 +214,7 @@
required required
disabled={source.gitlabAppId} disabled={source.gitlabAppId}
readonly={source.gitlabAppId} readonly={source.gitlabAppId}
value={source.htmlUrl} bind:value={source.htmlUrl}
/> />
</div> </div>
<div class="grid grid-cols-2 items-center"> <div class="grid grid-cols-2 items-center">
@@ -218,6 +228,20 @@
value={source.apiUrl} value={source.apiUrl}
/> />
</div> </div>
<div class="grid grid-cols-2 items-center">
<label for="customPort" class="text-base font-bold text-stone-100">Custom SSH Port</label>
<input
name="customPort"
id="customPort"
disabled={!selfHosted}
readonly={!selfHosted}
required
bind:value={source.customPort}
/>
<Explainer
text="If you use a self-hosted version of Git, you can provide custom port for all the Git related actions."
/>
</div>
<div class="grid grid-cols-2 items-start"> <div class="grid grid-cols-2 items-start">
<div class="flex-col"> <div class="flex-col">
<label for="oauthId" class="pt-2 text-base font-bold text-stone-100" <label for="oauthId" class="pt-2 text-base font-bold text-stone-100"