Gitee

by normal-coder
Verified
  • operations
import { z } from "zod"; import { giteeRequest, validateOwnerName, validateRepositoryName, getGiteeApiBaseUrl } from "../common/utils.js"; import { GiteeDirectoryContentSchema, GiteeFileContentSchema, GiteeFileOperationResultSchema } from "../common/types.js"; // Schema definitions export const GetFileContentsSchema = z.object({ // 仓库所属空间地址 (企业、组织或个人的地址 path) owner: z.string().describe("Repository owner path (enterprise, organization, or personal path)"), // 仓库路径 (path) repo: z.string().describe("Repository path"), // 文件路径 path: z.string().describe("File path"), // 分支名称,默认为仓库的默认分支 branch: z.string().optional().describe("Branch name, defaults to the repository's default branch"), }); export const CreateOrUpdateFileSchema = z.object({ // 仓库所属空间地址 (企业、组织或个人的地址 path) owner: z.string().describe("Repository owner path (enterprise, organization, or personal path)"), // 仓库路径 (path) repo: z.string().describe("Repository path"), // 文件路径 path: z.string().describe("File path"), // 文件内容 content: z.string().describe("File content"), // 提交信息 message: z.string().describe("Commit message"), // 分支名称,默认为仓库的默认分支 branch: z.string().optional().describe("Branch name, defaults to the repository's default branch"), // 文件的 SHA,更新文件时必须提供 sha: z.string().optional().describe("File SHA, required when updating an existing file"), }); export const PushFilesSchema = z.object({ // 仓库所属空间地址 (企业、组织或个人的地址 path) owner: z.string().describe("Repository owner path (enterprise, organization, or personal path)"), // 仓库路径 (path) repo: z.string().describe("Repository path"), // 分支名称,默认为仓库的默认分支 branch: z.string().optional().describe("Branch name, defaults to the repository's default branch"), // 提交信息 message: z.string().describe("Commit message"), // 要提交的文件列表 files: z.array(z.object({ // 文件路径 path: z.string().describe("File path"), // 文件内容 content: z.string().describe("File content"), })).describe("List of files to commit"), }); // Type exports export type GetFileContentsOptions = z.infer<typeof GetFileContentsSchema>; export type CreateOrUpdateFileOptions = z.infer<typeof CreateOrUpdateFileSchema>; export type PushFilesOptions = z.infer<typeof PushFilesSchema>; // Function implementations export async function getFileContents( owner: string, repo: string, path: string, branch?: string ) { owner = validateOwnerName(owner); repo = validateRepositoryName(repo); const url = new URL(`${getGiteeApiBaseUrl()}/repos/${owner}/${repo}/contents/${path}`); if (branch) { url.searchParams.append("ref", branch); } const response = await giteeRequest(url.toString(), "GET"); // Determine whether it is a file or directory based on the return type. if (Array.isArray(response)) { return GiteeDirectoryContentSchema.parse(response); } else { return GiteeFileContentSchema.parse(response); } } export async function createOrUpdateFile( owner: string, repo: string, path: string, content: string, message: string, branch?: string, sha?: string ) { owner = validateOwnerName(owner); repo = validateRepositoryName(repo); // Base64 encode the content const contentBase64 = Buffer.from(content).toString("base64"); const url = `/repos/${owner}/${repo}/contents/${path}`; const body: Record<string, string> = { content: contentBase64, message, }; if (branch) { body.branch = branch; } if (sha) { body.sha = sha; } const method = sha ? "PUT" : "POST"; const response = await giteeRequest(url, method, body); return GiteeFileOperationResultSchema.parse(response); } export async function pushFiles( owner: string, repo: string, branch: string | undefined, files: { path: string; content: string }[], message: string ) { // Since the Gitee API does not support submitting multiple files in a single commit, we need to submit them one by one. // This simplification assumes that Git Tree API is used to implement batch submission. const results = []; for (const file of files) { try { // Try to get the file contents, to determine whether it is created or updated let sha: string | undefined; try { const existingFile = await getFileContents(owner, repo, file.path, branch); if (!Array.isArray(existingFile)) { sha = existingFile.sha; } } catch (error) { // The file does not exist, creating a new file. } const result = await createOrUpdateFile( owner, repo, file.path, file.content, message, branch, sha ); results.push({ path: file.path, success: true, result, }); } catch (error) { results.push({ path: file.path, success: false, error: error instanceof Error ? error.message : String(error), }); } } return { message: `已处理 ${results.length} 个文件`, results, }; }