gogs-client.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. /**
  2. * Gogs API Client
  3. * Provides methods to interact with a Gogs server REST API
  4. */
  5. import axios, { AxiosInstance } from 'axios';
  6. import type {
  7. GogsUser,
  8. GogsRepository,
  9. GogsSearchResponse,
  10. GogsFileContent,
  11. GogsBranch,
  12. GogsCommit,
  13. GogsConfig,
  14. GogsIssue,
  15. GogsIssueComment,
  16. GogsLabel,
  17. GogsOrganization,
  18. GogsTeam,
  19. } from './types.js';
  20. export class GogsClient {
  21. private client: AxiosInstance;
  22. private serverUrl: string;
  23. constructor(config: GogsConfig) {
  24. this.serverUrl = config.serverUrl.replace(/\/$/, '');
  25. this.client = axios.create({
  26. baseURL: `${this.serverUrl}/api/v1`,
  27. headers: {
  28. 'Content-Type': 'application/json',
  29. ...(config.accessToken && { Authorization: `token ${config.accessToken}` }),
  30. },
  31. });
  32. }
  33. /**
  34. * Get information about the authenticated user
  35. */
  36. async getCurrentUser(): Promise<GogsUser> {
  37. const response = await this.client.get<GogsUser>('/user');
  38. return response.data;
  39. }
  40. /**
  41. * Get information about a specific user
  42. */
  43. async getUser(username: string): Promise<GogsUser> {
  44. const response = await this.client.get<GogsUser>(`/users/${username}`);
  45. return response.data;
  46. }
  47. /**
  48. * Search for users
  49. */
  50. async searchUsers(query: string, limit: number = 10): Promise<GogsUser[]> {
  51. const response = await this.client.get<GogsSearchResponse<GogsUser>>('/users/search', {
  52. params: { q: query, limit },
  53. });
  54. return response.data.data;
  55. }
  56. /**
  57. * List repositories for the authenticated user
  58. */
  59. async listMyRepositories(): Promise<GogsRepository[]> {
  60. const response = await this.client.get<GogsRepository[]>('/user/repos');
  61. return response.data;
  62. }
  63. /**
  64. * List repositories for a specific user
  65. */
  66. async listUserRepositories(username: string): Promise<GogsRepository[]> {
  67. const response = await this.client.get<GogsRepository[]>(`/users/${username}/repos`);
  68. return response.data;
  69. }
  70. /**
  71. * Search for repositories
  72. */
  73. async searchRepositories(
  74. query: string,
  75. options?: { uid?: number; limit?: number; page?: number }
  76. ): Promise<GogsRepository[]> {
  77. const response = await this.client.get<GogsSearchResponse<GogsRepository>>('/repos/search', {
  78. params: {
  79. q: query,
  80. uid: options?.uid || 0,
  81. limit: options?.limit || 10,
  82. page: options?.page || 1,
  83. },
  84. });
  85. return response.data.data;
  86. }
  87. /**
  88. * Get information about a specific repository
  89. */
  90. async getRepository(owner: string, repo: string): Promise<GogsRepository> {
  91. const response = await this.client.get<GogsRepository>(`/repos/${owner}/${repo}`);
  92. return response.data;
  93. }
  94. /**
  95. * Create a new repository
  96. */
  97. async createRepository(data: {
  98. name: string;
  99. description?: string;
  100. private?: boolean;
  101. auto_init?: boolean;
  102. gitignores?: string;
  103. license?: string;
  104. readme?: string;
  105. }): Promise<GogsRepository> {
  106. const response = await this.client.post<GogsRepository>('/user/repos', data);
  107. return response.data;
  108. }
  109. /**
  110. * Delete a repository
  111. */
  112. async deleteRepository(owner: string, repo: string): Promise<void> {
  113. await this.client.delete(`/repos/${owner}/${repo}`);
  114. }
  115. /**
  116. * Get file or directory contents
  117. */
  118. async getContents(
  119. owner: string,
  120. repo: string,
  121. path: string,
  122. ref?: string
  123. ): Promise<GogsFileContent | GogsFileContent[]> {
  124. const response = await this.client.get<GogsFileContent | GogsFileContent[]>(
  125. `/repos/${owner}/${repo}/contents/${path}`,
  126. {
  127. params: ref ? { ref } : undefined,
  128. }
  129. );
  130. return response.data;
  131. }
  132. /**
  133. * Get raw file content
  134. */
  135. async getRawContent(owner: string, repo: string, ref: string, path: string): Promise<string> {
  136. const response = await this.client.get<string>(
  137. `/repos/${owner}/${repo}/raw/${ref}/${path}`,
  138. {
  139. responseType: 'text',
  140. }
  141. );
  142. return response.data;
  143. }
  144. /**
  145. * List branches in a repository
  146. */
  147. async listBranches(owner: string, repo: string): Promise<GogsBranch[]> {
  148. const response = await this.client.get<GogsBranch[]>(`/repos/${owner}/${repo}/branches`);
  149. return response.data;
  150. }
  151. /**
  152. * Get commits from a repository
  153. */
  154. async getCommits(
  155. owner: string,
  156. repo: string,
  157. options?: { sha?: string; page?: number }
  158. ): Promise<GogsCommit[]> {
  159. const response = await this.client.get<GogsCommit[]>(`/repos/${owner}/${repo}/commits`, {
  160. params: {
  161. sha: options?.sha,
  162. page: options?.page || 1,
  163. },
  164. });
  165. return response.data;
  166. }
  167. /**
  168. * List issues in a repository
  169. */
  170. async listIssues(
  171. owner: string,
  172. repo: string,
  173. options?: {
  174. state?: 'open' | 'closed' | 'all';
  175. labels?: string;
  176. page?: number;
  177. per_page?: number;
  178. }
  179. ): Promise<GogsIssue[]> {
  180. const response = await this.client.get<GogsIssue[]>(`/repos/${owner}/${repo}/issues`, {
  181. params: {
  182. state: options?.state || 'open',
  183. labels: options?.labels,
  184. page: options?.page || 1,
  185. per_page: options?.per_page || 30,
  186. },
  187. });
  188. return response.data;
  189. }
  190. /**
  191. * Get a specific issue
  192. */
  193. async getIssue(owner: string, repo: string, number: number): Promise<GogsIssue> {
  194. const response = await this.client.get<GogsIssue>(`/repos/${owner}/${repo}/issues/${number}`);
  195. return response.data;
  196. }
  197. /**
  198. * Create a new issue
  199. */
  200. async createIssue(
  201. owner: string,
  202. repo: string,
  203. data: {
  204. title: string;
  205. body?: string;
  206. assignee?: string;
  207. milestone?: number;
  208. labels?: number[];
  209. }
  210. ): Promise<GogsIssue> {
  211. const response = await this.client.post<GogsIssue>(
  212. `/repos/${owner}/${repo}/issues`,
  213. data
  214. );
  215. return response.data;
  216. }
  217. /**
  218. * Update an existing issue
  219. */
  220. async updateIssue(
  221. owner: string,
  222. repo: string,
  223. number: number,
  224. data: {
  225. title?: string;
  226. body?: string;
  227. assignee?: string;
  228. milestone?: number;
  229. state?: 'open' | 'closed';
  230. labels?: number[];
  231. }
  232. ): Promise<GogsIssue> {
  233. const response = await this.client.patch<GogsIssue>(
  234. `/repos/${owner}/${repo}/issues/${number}`,
  235. data
  236. );
  237. return response.data;
  238. }
  239. /**
  240. * List comments on an issue
  241. */
  242. async listIssueComments(
  243. owner: string,
  244. repo: string,
  245. number: number
  246. ): Promise<GogsIssueComment[]> {
  247. const response = await this.client.get<GogsIssueComment[]>(
  248. `/repos/${owner}/${repo}/issues/${number}/comments`
  249. );
  250. return response.data;
  251. }
  252. /**
  253. * Create a comment on an issue
  254. */
  255. async createIssueComment(
  256. owner: string,
  257. repo: string,
  258. number: number,
  259. body: string
  260. ): Promise<GogsIssueComment> {
  261. const response = await this.client.post<GogsIssueComment>(
  262. `/repos/${owner}/${repo}/issues/${number}/comments`,
  263. { body }
  264. );
  265. return response.data;
  266. }
  267. /**
  268. * Edit a comment on an issue
  269. */
  270. async updateIssueComment(
  271. owner: string,
  272. repo: string,
  273. commentId: number,
  274. body: string
  275. ): Promise<GogsIssueComment> {
  276. const response = await this.client.patch<GogsIssueComment>(
  277. `/repos/${owner}/${repo}/issues/comments/${commentId}`,
  278. { body }
  279. );
  280. return response.data;
  281. }
  282. /**
  283. * List all labels in a repository
  284. */
  285. async listLabels(owner: string, repo: string): Promise<GogsLabel[]> {
  286. const response = await this.client.get<GogsLabel[]>(`/repos/${owner}/${repo}/labels`);
  287. return response.data;
  288. }
  289. /**
  290. * Get a specific label by ID
  291. */
  292. async getLabel(owner: string, repo: string, labelId: number): Promise<GogsLabel> {
  293. const response = await this.client.get<GogsLabel>(`/repos/${owner}/${repo}/labels/${labelId}`);
  294. return response.data;
  295. }
  296. /**
  297. * Create a new label
  298. */
  299. async createLabel(
  300. owner: string,
  301. repo: string,
  302. data: {
  303. name: string;
  304. color: string;
  305. }
  306. ): Promise<GogsLabel> {
  307. const response = await this.client.post<GogsLabel>(
  308. `/repos/${owner}/${repo}/labels`,
  309. data
  310. );
  311. return response.data;
  312. }
  313. /**
  314. * Update an existing label
  315. */
  316. async updateLabel(
  317. owner: string,
  318. repo: string,
  319. labelId: number,
  320. data: {
  321. name?: string;
  322. color?: string;
  323. }
  324. ): Promise<GogsLabel> {
  325. const response = await this.client.patch<GogsLabel>(
  326. `/repos/${owner}/${repo}/labels/${labelId}`,
  327. data
  328. );
  329. return response.data;
  330. }
  331. /**
  332. * Delete a label
  333. */
  334. async deleteLabel(owner: string, repo: string, labelId: number): Promise<void> {
  335. await this.client.delete(`/repos/${owner}/${repo}/labels/${labelId}`);
  336. }
  337. /**
  338. * List labels on a specific issue
  339. */
  340. async listIssueLabels(owner: string, repo: string, issueNumber: number): Promise<GogsLabel[]> {
  341. const response = await this.client.get<GogsLabel[]>(
  342. `/repos/${owner}/${repo}/issues/${issueNumber}/labels`
  343. );
  344. return response.data;
  345. }
  346. /**
  347. * Add labels to an issue
  348. */
  349. async addIssueLabels(
  350. owner: string,
  351. repo: string,
  352. issueNumber: number,
  353. labelIds: number[]
  354. ): Promise<GogsLabel[]> {
  355. const response = await this.client.post<GogsLabel[]>(
  356. `/repos/${owner}/${repo}/issues/${issueNumber}/labels`,
  357. { labels: labelIds }
  358. );
  359. return response.data;
  360. }
  361. /**
  362. * Remove a label from an issue
  363. */
  364. async removeIssueLabel(
  365. owner: string,
  366. repo: string,
  367. issueNumber: number,
  368. labelId: number
  369. ): Promise<void> {
  370. await this.client.delete(`/repos/${owner}/${repo}/issues/${issueNumber}/labels/${labelId}`);
  371. }
  372. /**
  373. * Replace all labels on an issue
  374. */
  375. async replaceIssueLabels(
  376. owner: string,
  377. repo: string,
  378. issueNumber: number,
  379. labelIds: number[]
  380. ): Promise<GogsLabel[]> {
  381. const response = await this.client.put<GogsLabel[]>(
  382. `/repos/${owner}/${repo}/issues/${issueNumber}/labels`,
  383. { labels: labelIds }
  384. );
  385. return response.data;
  386. }
  387. /**
  388. * Remove all labels from an issue
  389. */
  390. async removeAllIssueLabels(
  391. owner: string,
  392. repo: string,
  393. issueNumber: number
  394. ): Promise<void> {
  395. await this.client.delete(`/repos/${owner}/${repo}/issues/${issueNumber}/labels`);
  396. }
  397. /**
  398. * List organizations for the authenticated user
  399. */
  400. async listUserOrganizations(): Promise<GogsOrganization[]> {
  401. const response = await this.client.get<GogsOrganization[]>('/user/orgs');
  402. return response.data;
  403. }
  404. /**
  405. * List public organizations for a specific user
  406. */
  407. async listPublicOrganizations(username: string): Promise<GogsOrganization[]> {
  408. const response = await this.client.get<GogsOrganization[]>(`/users/${username}/orgs`);
  409. return response.data;
  410. }
  411. /**
  412. * Get information about a specific organization
  413. */
  414. async getOrganization(orgname: string): Promise<GogsOrganization> {
  415. const response = await this.client.get<GogsOrganization>(`/orgs/${orgname}`);
  416. return response.data;
  417. }
  418. /**
  419. * Update an organization
  420. */
  421. async updateOrganization(
  422. orgname: string,
  423. data: {
  424. full_name?: string;
  425. description?: string;
  426. website?: string;
  427. location?: string;
  428. }
  429. ): Promise<GogsOrganization> {
  430. const response = await this.client.patch<GogsOrganization>(`/orgs/${orgname}`, data);
  431. return response.data;
  432. }
  433. /**
  434. * Add or update organization membership
  435. */
  436. async addOrganizationMember(
  437. orgname: string,
  438. username: string,
  439. role: 'admin' | 'member'
  440. ): Promise<void> {
  441. await this.client.put(`/orgs/${orgname}/memberships/${username}`, { role });
  442. }
  443. /**
  444. * List teams in an organization
  445. */
  446. async listOrganizationTeams(orgname: string): Promise<GogsTeam[]> {
  447. const response = await this.client.get<GogsTeam[]>(`/orgs/${orgname}/teams`);
  448. return response.data;
  449. }
  450. }