import { execSync } from 'child_process'; import { Relace } from './client'; function ensureGitAvailable() { try { execSync('git --version', { stdio: 'ignore' }); } catch { throw new Error('Git CLI is not installed or not found in PATH.'); } } /** * Helper class that provides Git operations to the SDK. */ class GitHelper { constructor( private client: Relace, private rootPath: string, ) {} /** * Clone a Git repository. */ clone(options: { repoId: string; depth?: number; branch?: string; quiet?: boolean; args?: string[] }) { if (!this.rootPath) { throw new Error('No repository path provided. Please specify in git'); } const { repoId, depth = 1, branch, quiet = true, args = [] } = options; const branchArg = branch ? `-b ${branch}` : ''; const quietArg = quiet ? '--quiet' : ''; const extraArgs = args.join(' '); // Access API token from the client const apiToken = this.client.apiKey; const repoUrl = `https://token:${apiToken}@api.relace.run/v1/repo/${repoId}.git`; ensureGitAvailable(); const cmd = `git clone ${branchArg} --depth ${depth} ${quietArg} ${extraArgs} ${repoUrl} ${this.rootPath}`; execSync(cmd, { stdio: 'inherit' }); } /** * Fetch updates from remote repository (optionally for a specific branch) */ fetch(options?: { branch?: string }) { if (!this.rootPath) { throw new Error('No repository path provided. Please specify in git'); } const { branch } = options || {}; const branchArg = branch ? branch : ''; const cmd = branchArg ? `git -C ${this.rootPath} fetch origin ${branchArg}` : `git -C ${this.rootPath} fetch`; ensureGitAvailable(); execSync(cmd, { stdio: 'inherit' }); } /** * Stage files for commit */ add(options: { files?: string | string[] } = {}) { if (!this.rootPath) { throw new Error('No repository path provided. Please specify in git'); } const { files = '.' } = options; const filesArg = Array.isArray(files) ? files.join(' ') : files; ensureGitAvailable(); execSync(`git -C ${this.rootPath} add ${filesArg}`, { stdio: 'inherit' }); return this; } /** * Commit staged files */ commit(options: { message: string }) { const { message } = options; if (!this.rootPath) { throw new Error('No repository path provided. Please specify in git'); } if (!message) { throw new Error('Please specify a commit message'); } ensureGitAvailable(); execSync(`git -C ${this.rootPath} commit -m "${message}"`, { stdio: 'inherit' }); return this; } /** * Push commits to remote */ push(options: { branch?: string } = {}) { if (!this.rootPath) { throw new Error('No repository path provided. Please specify in git'); } ensureGitAvailable(); const { branch } = options; const branchArg = branch ? branch : execSync(`git -C ${this.rootPath} rev-parse --abbrev-ref HEAD`, { encoding: 'utf8' }); execSync(`git -C ${this.rootPath} push -u origin ${branchArg}`, { stdio: 'inherit' }); } /** * Pull a repo (optionally from a specific branch) */ pull(options?: { branch?: string }) { if (!this.rootPath) { throw new Error('No repository path provided. Please specify in git'); } const { branch } = options || {}; const branchArg = branch ? branch : ''; const cmd = branchArg ? `git -C ${this.rootPath} pull origin ${branchArg}` : `git -C ${this.rootPath} pull`; ensureGitAvailable(); execSync(cmd, { stdio: 'inherit' }); } /** * Checkout a Git branch. */ checkoutBranch(options: { branch: string; newBranch?: boolean }) { const { branch, newBranch } = options; if (!this.rootPath) { throw new Error('No repository path provided. Please specify in git'); } const args = newBranch ? '-b' : ''; ensureGitAvailable(); execSync(`git -C ${this.rootPath} checkout ${args} ${branch}`, { stdio: 'inherit' }); } /** * Run a generic git command. */ command(options: { cmd: string }) { const { cmd } = options; if (!this.rootPath) { throw new Error('No repository path provided. Please specify in git'); } if (!cmd) { throw new Error('Please provide a Git command to execute.'); } ensureGitAvailable(); execSync(`git -C ${this.rootPath} ${cmd}`, { stdio: 'inherit' }); return this; } } /** * Attach git helpers to the SDK prototype. */ export function attachGitSupport(ClientClass: typeof Relace) { (ClientClass.prototype as any).git = function (repoPath: string) { return new GitHelper(this, repoPath); }; } export { GitHelper };