93b415c53e
- Make project_id nullable in git_repositories table (migration) - Allow external repos not tied to any project - Update validation to allow user-owned external repos in git mounts - Add /projects/repositories endpoint to list all user repos - Update frontend to fetch all user repos for git mount selector - TypeScript and build pass
286 lines
6.8 KiB
TypeScript
286 lines
6.8 KiB
TypeScript
import { apiClient } from "./client";
|
|
|
|
export interface GitRepository {
|
|
id: string;
|
|
name: string;
|
|
path: string;
|
|
project_id: string;
|
|
owner_id: string;
|
|
is_mirror: boolean;
|
|
remote_url: string | null;
|
|
ssh_key_id: string | null;
|
|
last_push: string | null;
|
|
created_at: string | null;
|
|
}
|
|
|
|
export interface GitRepositoryCreate {
|
|
name: string;
|
|
remote_url?: string;
|
|
force_original_url?: boolean;
|
|
ssh_key_id?: string;
|
|
}
|
|
|
|
export interface URLParseResult {
|
|
original_url: string;
|
|
base_url: string | null;
|
|
is_valid_clone_url: boolean;
|
|
needs_parsing: boolean;
|
|
host: string | null;
|
|
message: string;
|
|
error_code: string | null;
|
|
}
|
|
|
|
export async function parseGitUrl(url: string): Promise<URLParseResult> {
|
|
const response = await apiClient.post("/projects/repositories/parse-url", { url });
|
|
return response.data;
|
|
}
|
|
|
|
export async function listRepositories(projectId: string): Promise<GitRepository[]> {
|
|
const response = await apiClient.get(`/projects/${projectId}/repositories`);
|
|
return response.data;
|
|
}
|
|
|
|
export async function listAllUserRepositories(): Promise<GitRepository[]> {
|
|
const response = await apiClient.get<GitRepository[]>("/projects/repositories");
|
|
return response.data;
|
|
}
|
|
|
|
export async function createRepository(
|
|
projectId: string,
|
|
data: GitRepositoryCreate
|
|
): Promise<GitRepository> {
|
|
const response = await apiClient.post(`/projects/${projectId}/repositories`, data);
|
|
return response.data;
|
|
}
|
|
|
|
export async function deleteRepository(projectId: string, repoId: string): Promise<void> {
|
|
await apiClient.delete(`/projects/${projectId}/repositories/${repoId}`);
|
|
}
|
|
|
|
export async function updateRepositorySshKey(
|
|
projectId: string,
|
|
repoId: string,
|
|
sshKeyId: string | null
|
|
): Promise<GitRepository> {
|
|
const response = await apiClient.patch(
|
|
`/projects/${projectId}/repositories/${repoId}/ssh-key`,
|
|
{ ssh_key_id: sshKeyId }
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
export interface Branch {
|
|
name: string;
|
|
is_default: boolean;
|
|
last_commit: string | null;
|
|
}
|
|
|
|
export interface BranchesResponse {
|
|
branches: Branch[];
|
|
default_branch: string;
|
|
}
|
|
|
|
export async function listRepositoryBranches(
|
|
projectId: string,
|
|
repoId: string
|
|
): Promise<BranchesResponse> {
|
|
const response = await apiClient.get(
|
|
`/projects/${projectId}/repositories/${repoId}/branches`
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
export interface CommitHistoryEntry {
|
|
hash: string;
|
|
short_hash: string;
|
|
message: string;
|
|
author_name: string;
|
|
author_email: string;
|
|
author_date: string;
|
|
refs: string[];
|
|
graph_symbol: string;
|
|
graph_depth: number;
|
|
}
|
|
|
|
export interface CommitHistoryResponse {
|
|
commits: CommitHistoryEntry[];
|
|
branches: string[];
|
|
tags: string[];
|
|
}
|
|
|
|
export async function getRepositoryHistory(
|
|
projectId: string,
|
|
repoId: string,
|
|
branch?: string,
|
|
limit?: number
|
|
): Promise<CommitHistoryResponse> {
|
|
const searchParams = new URLSearchParams();
|
|
if (branch) searchParams.set("branch", branch);
|
|
if (limit) searchParams.set("limit", String(limit));
|
|
const queryString = searchParams.toString();
|
|
const params = queryString ? `?${queryString}` : "";
|
|
const response = await apiClient.get(`/projects/${projectId}/repositories/${repoId}/history${params}`);
|
|
return response.data;
|
|
}
|
|
|
|
export interface CommitDetail {
|
|
hash: string;
|
|
short_hash: string;
|
|
message: string;
|
|
author_name: string;
|
|
author_email: string;
|
|
author_date: string;
|
|
committer_name: string;
|
|
committer_email: string;
|
|
committer_date: string;
|
|
stats: {
|
|
additions: number;
|
|
deletions: number;
|
|
files_changed: number;
|
|
};
|
|
diff: string;
|
|
parents: string[];
|
|
}
|
|
|
|
export async function getCommitDetail(
|
|
projectId: string,
|
|
repoId: string,
|
|
commitHash: string
|
|
): Promise<CommitDetail> {
|
|
const response = await apiClient.get(
|
|
`/projects/${projectId}/repositories/${repoId}/commits/${commitHash}`
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
// Git Control API
|
|
|
|
export interface GitStatus {
|
|
branch: string;
|
|
modified: string[];
|
|
added: string[];
|
|
deleted: string[];
|
|
untracked: string[];
|
|
renamed: string[];
|
|
ahead: number;
|
|
behind: number;
|
|
}
|
|
|
|
export async function getRepositoryStatus(
|
|
projectId: string,
|
|
repoId: string
|
|
): Promise<GitStatus> {
|
|
const response = await apiClient.get(
|
|
`/projects/${projectId}/repositories/${repoId}/status`
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
export async function createBranch(
|
|
projectId: string,
|
|
repoId: string,
|
|
name: string,
|
|
baseBranch: string = "HEAD"
|
|
): Promise<{ message: string; branch: string }> {
|
|
const response = await apiClient.post(
|
|
`/projects/${projectId}/repositories/${repoId}/branches`,
|
|
{ name, base_branch: baseBranch }
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
export async function deleteBranch(
|
|
projectId: string,
|
|
repoId: string,
|
|
branchName: string,
|
|
force: boolean = false
|
|
): Promise<{ message: string }> {
|
|
const response = await apiClient.delete(
|
|
`/projects/${projectId}/repositories/${repoId}/branches/${branchName}?force=${force}`
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
export async function checkoutBranch(
|
|
projectId: string,
|
|
repoId: string,
|
|
branch: string
|
|
): Promise<{ message: string; branch: string }> {
|
|
const response = await apiClient.post(
|
|
`/projects/${projectId}/repositories/${repoId}/checkout`,
|
|
{ branch }
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
export interface CommitResponse {
|
|
commit_hash: string;
|
|
message: string;
|
|
}
|
|
|
|
export async function commitChanges(
|
|
projectId: string,
|
|
repoId: string,
|
|
message: string,
|
|
files?: string[]
|
|
): Promise<CommitResponse> {
|
|
const response = await apiClient.post(
|
|
`/projects/${projectId}/repositories/${repoId}/commit`,
|
|
{ message, files }
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
export async function fetchRepository(
|
|
projectId: string,
|
|
repoId: string
|
|
): Promise<{ message: string }> {
|
|
const response = await apiClient.post(
|
|
`/projects/${projectId}/repositories/${repoId}/fetch`
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
export async function pullRepository(
|
|
projectId: string,
|
|
repoId: string,
|
|
branch?: string
|
|
): Promise<{ message: string }> {
|
|
const params = branch ? `?branch=${branch}` : "";
|
|
const response = await apiClient.post(
|
|
`/projects/${projectId}/repositories/${repoId}/pull${params}`
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
export async function pushRepository(
|
|
projectId: string,
|
|
repoId: string,
|
|
branch?: string
|
|
): Promise<{ message: string }> {
|
|
const params = branch ? `?branch=${branch}` : "";
|
|
const response = await apiClient.post(
|
|
`/projects/${projectId}/repositories/${repoId}/push${params}`
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
export interface MergeResponse {
|
|
commit_hash: string;
|
|
message: string;
|
|
}
|
|
|
|
export async function mergeBranches(
|
|
projectId: string,
|
|
repoId: string,
|
|
sourceBranch: string,
|
|
targetBranch?: string,
|
|
message?: string
|
|
): Promise<MergeResponse> {
|
|
const response = await apiClient.post(
|
|
`/projects/${projectId}/repositories/${repoId}/merge`,
|
|
{ source_branch: sourceBranch, target_branch: targetBranch, message }
|
|
);
|
|
return response.data;
|
|
}
|