PRININIT / src /api-checkout.ts
Rachit-Tw's picture
Upload 50 files
7d9309d verified
Raw
History Blame Contribute Delete
5.49 kB
import {getCurrentContext} from './context'
/**
* File-based checkout using GitHub Contents API instead of git clone
* Much faster, cheaper, and more reliable
*/
export interface FileInfo {
path: string
content: string
sha: string
}
export class ApiCheckout {
private octokit: any
private owner: string
private repo: string
private commitSha: string
private branchName?: string
private cache: Map<string, FileInfo> = new Map()
constructor(
probotContext?: any,
options?: {owner?: string; repo?: string; ref?: string; branch?: string}
) {
// Use passed probotContext or get from async context
const ctx = probotContext || getCurrentContext()
if (!ctx && !options)
throw new Error('No context available and no options provided')
this.octokit = ctx?.probotContext?.octokit || ctx?.octokit
this.owner = options?.owner || ctx?.repo?.owner
this.repo = options?.repo || ctx?.repo?.repo
// Primary source: options
if (options?.ref) {
this.commitSha = options.ref
} else {
// Fallback: pull_request payload
const pullRequest =
ctx?.probotContext?.payload?.pull_request || ctx?.payload?.pull_request
if (pullRequest?.head?.sha) {
this.commitSha = pullRequest.head.sha
} else {
throw new Error(
'No commit SHA (ref) available for checkout. For issue_comment events, please provide ref in options.'
)
}
}
this.branchName =
options?.branch ||
ctx?.probotContext?.payload?.pull_request?.head?.ref ||
ctx?.payload?.pull_request?.head?.ref
}
/**
* Get file content via GitHub API
*/
async getFile(path: string): Promise<FileInfo> {
// Check cache first
if (this.cache.has(path)) {
return this.cache.get(path)!
}
try {
const response = await this.octokit.repos.getContent({
owner: this.owner,
repo: this.repo,
path: path,
ref: this.commitSha
})
// Handle both file and directory responses
if (Array.isArray(response.data)) {
throw new Error(`Path ${path} is a directory, not a file`)
}
const content = Buffer.from(response.data.content, 'base64').toString(
'utf-8'
)
const fileInfo: FileInfo = {
path,
content,
sha: response.data.sha
}
// Cache the result
this.cache.set(path, fileInfo)
return fileInfo
} catch (error) {
throw new Error(`Failed to get file ${path}: ${error}`)
}
}
/**
* Update file content via GitHub API
*/
async updateFile(
path: string,
newContent: string,
message: string
): Promise<string> {
const currentFile = await this.getFile(path)
try {
const response = await this.octokit.repos.createOrUpdateFileContents({
owner: this.owner,
repo: this.repo,
path: path,
message: message,
content: Buffer.from(newContent).toString('base64'),
sha: currentFile.sha,
branch: this.branchName || this.commitSha
})
// Update cache
const updatedFile: FileInfo = {
path,
content: newContent,
sha: response.data.commit.sha
}
this.cache.set(path, updatedFile)
return response.data.commit.sha
} catch (error) {
throw new Error(`Failed to update file ${path}: ${error}`)
}
}
/**
* Create a new file via GitHub API
*/
async createFile(
path: string,
content: string,
message: string
): Promise<string> {
try {
const response = await this.octokit.repos.createOrUpdateFileContents({
owner: this.owner,
repo: this.repo,
path: path,
message: message,
content: Buffer.from(content).toString('base64'),
branch: this.branchName || this.commitSha
})
// Update cache
const newFile: FileInfo = {
path,
content,
sha: response.data.commit.sha
}
this.cache.set(path, newFile)
return response.data.commit.sha
} catch (error) {
throw new Error(`Failed to create file ${path}: ${error}`)
}
}
/**
* Get directory listing
*/
async getDirectory(path: string): Promise<string[]> {
try {
const response = await this.octokit.repos.getContent({
owner: this.owner,
repo: this.repo,
path: path,
ref: this.commitSha
})
if (!Array.isArray(response.data)) {
throw new Error(`Path ${path} is not a directory`)
}
return response.data
.filter((item: any) => item.type === 'file')
.map((item: any) => item.path)
} catch (error) {
throw new Error(`Failed to get directory ${path}: ${error}`)
}
}
/**
* Get repository tree structure
*/
async getTree(): Promise<string[]> {
try {
const response = await this.octokit.git.getTree({
owner: this.owner,
repo: this.repo,
tree_sha: this.commitSha,
recursive: true
})
return response.data.tree
.filter((item: any) => item.type === 'blob')
.map((item: any) => item.path)
} catch (error) {
throw new Error(`Failed to get repository tree: ${error}`)
}
}
}