-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathgithub.ts
More file actions
174 lines (145 loc) · 5.89 KB
/
github.ts
File metadata and controls
174 lines (145 loc) · 5.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import * as vscode from 'vscode';
export interface GitHubFile {
name: string;
path: string;
content?: string;
download_url?: string;
type: 'file' | 'dir';
}
export interface GitHubTreeItem {
path: string;
mode: string;
type: 'blob' | 'tree';
sha: string;
url: string;
}
export interface GitHubTree {
tree: GitHubTreeItem[];
truncated: boolean;
}
export class GitHubApiManager {
private baseUrl = 'https://api.github.com';
async getAuthenticatedUser(): Promise<any> {
const session = await vscode.authentication.getSession('github', ['repo'], { createIfNone: false });
if (!session) {
throw new Error('GitHub authentication required');
}
const response = await fetch(`${this.baseUrl}/user`, {
headers: {
'Authorization': `Bearer ${session.accessToken}`,
'Accept': 'application/vnd.github.v3+json',
'User-Agent': 'VS Code Prompts Sync Extension'
}
});
if (!response.ok) {
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
}
return response.json();
}
async getRepositoryTree(owner: string, repo: string, branch: string = 'master'): Promise<GitHubTree> {
const session = await vscode.authentication.getSession('github', ['repo'], { createIfNone: false });
if (!session) {
throw new Error('GitHub authentication required');
}
// First get the commit SHA for the branch
const branchResponse = await fetch(`${this.baseUrl}/repos/${owner}/${repo}/branches/${branch}`, {
headers: {
'Authorization': `Bearer ${session.accessToken}`,
'Accept': 'application/vnd.github.v3+json',
'User-Agent': 'VS Code Prompts Sync Extension'
}
});
if (!branchResponse.ok) {
throw new Error(`Failed to get branch info: ${branchResponse.status} ${branchResponse.statusText}`);
}
const branchData = await branchResponse.json();
const commitSha = branchData.commit.sha;
// Get the tree recursively
const treeResponse = await fetch(`${this.baseUrl}/repos/${owner}/${repo}/git/trees/${commitSha}?recursive=1`, {
headers: {
'Authorization': `Bearer ${session.accessToken}`,
'Accept': 'application/vnd.github.v3+json',
'User-Agent': 'VS Code Prompts Sync Extension'
}
});
if (!treeResponse.ok) {
throw new Error(`Failed to get repository tree: ${treeResponse.status} ${treeResponse.statusText}`);
}
return treeResponse.json();
}
async getFileContent(owner: string, repo: string, path: string, branch: string = 'master'): Promise<string> {
const session = await vscode.authentication.getSession('github', ['repo'], { createIfNone: false });
if (!session) {
throw new Error('GitHub authentication required');
}
console.log(`Fetching file content from ${owner}/${repo}/${path} on branch ${branch}`);
const response = await fetch(`${this.baseUrl}/repos/${owner}/${repo}/contents/${path}?ref=${branch}`, {
headers: {
'Authorization': `Bearer ${session.accessToken}`,
'Accept': 'application/vnd.github.v3+json',
'User-Agent': 'VS Code Prompts Sync Extension'
}
});
if (!response.ok) {
throw new Error(`Failed to get file content: ${response.status} ${response.statusText}`);
}
const data = await response.json();
if (data.content) {
// Content is base64 encoded
return Buffer.from(data.content, 'base64').toString('utf8');
}
throw new Error('No content found in file');
}
async getFileHash(owner: string, repo: string, path: string, branch: string = 'master'): Promise<string> {
const session = await vscode.authentication.getSession('github', ['repo'], { createIfNone: false });
if (!session) {
throw new Error('GitHub authentication required');
}
const response = await fetch(`${this.baseUrl}/repos/${owner}/${repo}/contents/${path}?ref=${branch}`, {
headers: {
'Authorization': `Bearer ${session.accessToken}`,
'Accept': 'application/vnd.github.v3+json',
'User-Agent': 'VS Code Prompts Sync Extension'
}
});
if (!response.ok) {
throw new Error(`Failed to get file hash: ${response.status} ${response.statusText}`);
}
const data = await response.json();
return data.sha;
}
parseRepositoryUrl(url: string): { owner: string; repo: string } {
// Handle different GitHub URL formats
const patterns = [
/github\.com\/([^\/]+)\/([^\/]+)(?:\.git)?$/,
/github\.com\/([^\/]+)\/([^\/]+)\/$/,
/github\.com\/([^\/]+)\/([^\/]+)$/
];
for (const pattern of patterns) {
const match = url.match(pattern);
if (match) {
return {
owner: match[1],
repo: match[2].replace(/\.git$/, '')
};
}
}
throw new Error(`Invalid GitHub repository URL: ${url}`);
}
async checkAuthentication(): Promise<boolean> {
try {
const session = await vscode.authentication.getSession('github', ['repo'], { createIfNone: false });
return !!session;
} catch {
return false;
}
}
async requestAuthentication(): Promise<boolean> {
try {
const session = await vscode.authentication.getSession('github', ['repo'], { createIfNone: true });
return !!session;
} catch {
return false;
}
}
}