diff --git a/backend/src/applications/dto/application.dto.ts b/backend/src/applications/dto/application.dto.ts index b27fe2c..659ca51 100644 --- a/backend/src/applications/dto/application.dto.ts +++ b/backend/src/applications/dto/application.dto.ts @@ -37,6 +37,16 @@ export class CreateApplicationDto { @IsString() gitUrl?: string; + @ApiPropertyOptional({ example: 'ghp_xxxxxxxxxxxxxxxxxxxx', description: 'Personal access token for private git repos' }) + @IsOptional() + @IsString() + gitToken?: string; + + @ApiPropertyOptional({ example: 'main', description: 'Git branch to clone (default: main)' }) + @IsOptional() + @IsString() + gitBranch?: string; + @ApiPropertyOptional({ example: { NODE_ENV: 'production', PORT: '3000' } }) @IsOptional() @IsObject() @@ -86,6 +96,21 @@ export class UpdateApplicationDto { @IsString() description?: string; + @ApiPropertyOptional() + @IsOptional() + @IsString() + gitUrl?: string; + + @ApiPropertyOptional({ description: 'Personal access token for private repos' }) + @IsOptional() + @IsString() + gitToken?: string; + + @ApiPropertyOptional({ description: 'Git branch to clone' }) + @IsOptional() + @IsString() + gitBranch?: string; + @ApiPropertyOptional() @IsOptional() @IsObject() diff --git a/backend/src/applications/entities/application.entity.ts b/backend/src/applications/entities/application.entity.ts index b903f80..03d91e5 100644 --- a/backend/src/applications/entities/application.entity.ts +++ b/backend/src/applications/entities/application.entity.ts @@ -32,6 +32,12 @@ export class Application { @Column({ nullable: true }) gitUrl: string; + @Column({ nullable: true }) + gitToken: string; // Personal access token for private repos + + @Column({ nullable: true }) + gitBranch: string; // Branch to clone (default: main) + @Column({ nullable: true }) codePath: string; // Path to uploaded zip diff --git a/backend/src/build/build.service.ts b/backend/src/build/build.service.ts index 136403a..86e74c9 100644 --- a/backend/src/build/build.service.ts +++ b/backend/src/build/build.service.ts @@ -149,13 +149,30 @@ export class BuildService { ], }); } else if (hasGitUrl) { + // Build the git clone URL โ€” inject token for private repos + let cloneUrl = app.gitUrl!; + if (app.gitToken) { + // Convert https://github.com/user/repo.git โ†’ https://@github.com/user/repo.git + // Also works for GitLab, Bitbucket, etc. + try { + const url = new URL(cloneUrl); + url.username = app.gitToken; + url.password = ''; // Some providers use token as username, others as password + cloneUrl = url.toString(); + } catch { + // If URL parsing fails, try simple injection after protocol + cloneUrl = cloneUrl.replace('https://', `https://${app.gitToken}@`); + } + } + const branch = app.gitBranch || 'main'; + // Clone git repo into /workspace/source, then copy our generated Dockerfile initContainers.push({ name: 'git-clone', image: 'alpine/git:2.43.0', command: ['sh', '-c', ` - echo ">>> Cloning ${app.gitUrl}" && - git clone --depth 1 ${app.gitUrl} /workspace-out/source && + echo ">>> Cloning branch '${branch}' from ${app.gitUrl}" && + git clone --depth 1 --branch ${branch} ${cloneUrl} /workspace-out/source && cp /dockerfile/Dockerfile /workspace-out/Dockerfile && echo ">>> Workspace contents:" && ls -la /workspace-out/source/ diff --git a/frontend/src/app/dashboard/apps/[id]/page.tsx b/frontend/src/app/dashboard/apps/[id]/page.tsx index 64882e7..fc27c4b 100644 --- a/frontend/src/app/dashboard/apps/[id]/page.tsx +++ b/frontend/src/app/dashboard/apps/[id]/page.tsx @@ -453,6 +453,18 @@ export default function AppDetailPage() {

Git repository connected

{app.gitUrl}

+
+ {app.gitBranch && ( + + ๐ŸŒฟ {app.gitBranch} + + )} + {app.gitToken && ( + + ๐Ÿ”‘ Private + + )} +
diff --git a/frontend/src/app/dashboard/deploy/page.tsx b/frontend/src/app/dashboard/deploy/page.tsx index cafef9f..ab5dedc 100644 --- a/frontend/src/app/dashboard/deploy/page.tsx +++ b/frontend/src/app/dashboard/deploy/page.tsx @@ -18,6 +18,8 @@ export default function DeployPage() { runtime: 'nodejs', databaseType: 'none', gitUrl: '', + gitToken: '', + gitBranch: '', envVars: {}, cpuRequest: '100m', cpuLimit: '500m', @@ -207,13 +209,42 @@ export default function DeployPage() { {sourceMethod === 'git' ? ( -
- setForm({ ...form, gitUrl: e.target.value })} - /> +
+
+ + setForm({ ...form, gitUrl: e.target.value })} + /> +
+
+ + setForm({ ...form, gitToken: e.target.value })} + /> +

+ GitHub: Personal Access Token ยท GitLab: Project Access Token ยท Leave empty for public repos +

+
+
+ + setForm({ ...form, gitBranch: e.target.value })} + /> +
) : (
@@ -454,6 +485,18 @@ export default function DeployPage() { : form.gitUrl || 'โ€”'}
+ {sourceMethod === 'git' && form.gitBranch && ( +
+ Branch + {form.gitBranch} +
+ )} + {sourceMethod === 'git' && form.gitToken && ( +
+ Auth + ๐Ÿ”‘ Token provided +
+ )}
CPU {form.cpuRequest} / {form.cpuLimit} diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 7570624..00e3b6b 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -16,6 +16,8 @@ export interface Application { runtime: 'nodejs' | 'laravel'; databaseType: 'mysql' | 'postgresql' | 'none'; gitUrl?: string; + gitToken?: string; + gitBranch?: string; codePath?: string; envVars?: Record; cpuRequest: string; @@ -84,6 +86,8 @@ export interface CreateApplicationDto { runtime: 'nodejs' | 'laravel'; databaseType: 'mysql' | 'postgresql' | 'none'; gitUrl?: string; + gitToken?: string; + gitBranch?: string; envVars?: Record; cpuRequest?: string; cpuLimit?: string;