/** * Gogs API Client * Provides methods to interact with a Gogs server REST API */ import axios, { AxiosInstance } from 'axios'; import type { GogsUser, GogsRepository, GogsSearchResponse, GogsFileContent, GogsBranch, GogsCommit, GogsConfig, GogsIssue, GogsIssueComment, GogsLabel, GogsMilestone, GogsOrganization, GogsTeam, GogsTree, GogsRelease, GogsCollaborator, GogsEmail, GogsPublicKey, GogsWebhook, GogsWebhookEvent, GogsWebhookType, GogsWebhookConfig, GogsFollower, } from './types.js'; export class GogsClient { private client: AxiosInstance; private serverUrl: string; constructor(config: GogsConfig) { this.serverUrl = config.serverUrl.replace(/\/$/, ''); this.client = axios.create({ baseURL: `${this.serverUrl}/api/v1`, headers: { 'Content-Type': 'application/json', ...(config.accessToken && { Authorization: `token ${config.accessToken}` }), }, }); } /** * Get information about the authenticated user */ async getCurrentUser(): Promise { const response = await this.client.get('/user'); return response.data; } /** * Get information about a specific user */ async getUser(username: string): Promise { const response = await this.client.get(`/users/${username}`); return response.data; } /** * Search for users */ async searchUsers(query: string, limit: number = 10): Promise { const response = await this.client.get>('/users/search', { params: { q: query, limit }, }); return response.data.data; } /** * List repositories for the authenticated user */ async listMyRepositories(): Promise { const response = await this.client.get('/user/repos'); return response.data; } /** * List repositories for a specific user */ async listUserRepositories(username: string): Promise { const response = await this.client.get(`/users/${username}/repos`); return response.data; } /** * Search for repositories */ async searchRepositories( query: string, options?: { uid?: number; limit?: number; page?: number } ): Promise { const response = await this.client.get>('/repos/search', { params: { q: query, uid: options?.uid || 0, limit: options?.limit || 10, page: options?.page || 1, }, }); return response.data.data; } /** * Get information about a specific repository */ async getRepository(owner: string, repo: string): Promise { const response = await this.client.get(`/repos/${owner}/${repo}`); return response.data; } /** * Create a new repository */ async createRepository(data: { name: string; description?: string; private?: boolean; auto_init?: boolean; gitignores?: string; license?: string; readme?: string; }): Promise { const response = await this.client.post('/user/repos', data); return response.data; } /** * Delete a repository */ async deleteRepository(owner: string, repo: string): Promise { await this.client.delete(`/repos/${owner}/${repo}`); } /** * Get file or directory contents */ async getContents( owner: string, repo: string, path: string, ref?: string ): Promise { const response = await this.client.get( `/repos/${owner}/${repo}/contents/${path}`, { params: ref ? { ref } : undefined, } ); return response.data; } /** * Get raw file content */ async getRawContent(owner: string, repo: string, ref: string, path: string): Promise { const response = await this.client.get( `/repos/${owner}/${repo}/raw/${ref}/${path}`, { responseType: 'text', } ); return response.data; } /** * List branches in a repository */ async listBranches(owner: string, repo: string): Promise { const response = await this.client.get(`/repos/${owner}/${repo}/branches`); return response.data; } /** * Get commits from a repository */ async getCommits( owner: string, repo: string, options?: { sha?: string; page?: number } ): Promise { const response = await this.client.get(`/repos/${owner}/${repo}/commits`, { params: { sha: options?.sha, page: options?.page || 1, }, }); return response.data; } /** * Get a git tree by SHA */ async getTree(owner: string, repo: string, sha: string): Promise { const response = await this.client.get(`/repos/${owner}/${repo}/git/trees/${sha}`); return response.data; } /** * List issues in a repository */ async listIssues( owner: string, repo: string, options?: { state?: 'open' | 'closed' | 'all'; labels?: string; page?: number; per_page?: number; } ): Promise { const response = await this.client.get(`/repos/${owner}/${repo}/issues`, { params: { state: options?.state || 'open', labels: options?.labels, page: options?.page || 1, per_page: options?.per_page || 30, }, }); return response.data; } /** * Get a specific issue */ async getIssue(owner: string, repo: string, number: number): Promise { const response = await this.client.get(`/repos/${owner}/${repo}/issues/${number}`); return response.data; } /** * Create a new issue */ async createIssue( owner: string, repo: string, data: { title: string; body?: string; assignee?: string; milestone?: number; labels?: number[]; } ): Promise { const response = await this.client.post( `/repos/${owner}/${repo}/issues`, data ); return response.data; } /** * Update an existing issue */ async updateIssue( owner: string, repo: string, number: number, data: { title?: string; body?: string; assignee?: string; milestone?: number; state?: 'open' | 'closed'; labels?: number[]; } ): Promise { const response = await this.client.patch( `/repos/${owner}/${repo}/issues/${number}`, data ); return response.data; } /** * List comments on an issue */ async listIssueComments( owner: string, repo: string, number: number ): Promise { const response = await this.client.get( `/repos/${owner}/${repo}/issues/${number}/comments` ); return response.data; } /** * Create a comment on an issue */ async createIssueComment( owner: string, repo: string, number: number, body: string ): Promise { const response = await this.client.post( `/repos/${owner}/${repo}/issues/${number}/comments`, { body } ); return response.data; } /** * Edit a comment on an issue */ async updateIssueComment( owner: string, repo: string, commentId: number, body: string ): Promise { const response = await this.client.patch( `/repos/${owner}/${repo}/issues/comments/${commentId}`, { body } ); return response.data; } /** * List all labels in a repository */ async listLabels(owner: string, repo: string): Promise { const response = await this.client.get(`/repos/${owner}/${repo}/labels`); return response.data; } /** * Get a specific label by ID */ async getLabel(owner: string, repo: string, labelId: number): Promise { const response = await this.client.get(`/repos/${owner}/${repo}/labels/${labelId}`); return response.data; } /** * Create a new label */ async createLabel( owner: string, repo: string, data: { name: string; color: string; } ): Promise { const response = await this.client.post( `/repos/${owner}/${repo}/labels`, data ); return response.data; } /** * Update an existing label */ async updateLabel( owner: string, repo: string, labelId: number, data: { name?: string; color?: string; } ): Promise { const response = await this.client.patch( `/repos/${owner}/${repo}/labels/${labelId}`, data ); return response.data; } /** * Delete a label */ async deleteLabel(owner: string, repo: string, labelId: number): Promise { await this.client.delete(`/repos/${owner}/${repo}/labels/${labelId}`); } /** * List labels on a specific issue */ async listIssueLabels(owner: string, repo: string, issueNumber: number): Promise { const response = await this.client.get( `/repos/${owner}/${repo}/issues/${issueNumber}/labels` ); return response.data; } /** * Add labels to an issue */ async addIssueLabels( owner: string, repo: string, issueNumber: number, labelIds: number[] ): Promise { const response = await this.client.post( `/repos/${owner}/${repo}/issues/${issueNumber}/labels`, { labels: labelIds } ); return response.data; } /** * Remove a label from an issue */ async removeIssueLabel( owner: string, repo: string, issueNumber: number, labelId: number ): Promise { await this.client.delete(`/repos/${owner}/${repo}/issues/${issueNumber}/labels/${labelId}`); } /** * Replace all labels on an issue */ async replaceIssueLabels( owner: string, repo: string, issueNumber: number, labelIds: number[] ): Promise { const response = await this.client.put( `/repos/${owner}/${repo}/issues/${issueNumber}/labels`, { labels: labelIds } ); return response.data; } /** * Remove all labels from an issue */ async removeAllIssueLabels( owner: string, repo: string, issueNumber: number ): Promise { await this.client.delete(`/repos/${owner}/${repo}/issues/${issueNumber}/labels`); } /** * List all milestones in a repository */ async listMilestones(owner: string, repo: string): Promise { const response = await this.client.get(`/repos/${owner}/${repo}/milestones`); return response.data; } /** * Get a specific milestone by ID */ async getMilestone(owner: string, repo: string, milestoneId: number): Promise { const response = await this.client.get(`/repos/${owner}/${repo}/milestones/${milestoneId}`); return response.data; } /** * Create a new milestone */ async createMilestone( owner: string, repo: string, data: { title: string; description?: string; due_on?: string; } ): Promise { const response = await this.client.post( `/repos/${owner}/${repo}/milestones`, data ); return response.data; } /** * Update an existing milestone */ async updateMilestone( owner: string, repo: string, milestoneId: number, data: { title?: string; description?: string; due_on?: string; state?: 'open' | 'closed'; } ): Promise { const response = await this.client.patch( `/repos/${owner}/${repo}/milestones/${milestoneId}`, data ); return response.data; } /** * Delete a milestone */ async deleteMilestone(owner: string, repo: string, milestoneId: number): Promise { await this.client.delete(`/repos/${owner}/${repo}/milestones/${milestoneId}`); } /** * List organizations for the authenticated user */ async listUserOrganizations(): Promise { const response = await this.client.get('/user/orgs'); return response.data; } /** * Create a new organization */ async createOrganization(data: { username: string; full_name?: string; description?: string; website?: string; location?: string; }): Promise { const response = await this.client.post('/user/orgs', data); return response.data; } /** * List public organizations for a specific user */ async listPublicOrganizations(username: string): Promise { const response = await this.client.get(`/users/${username}/orgs`); return response.data; } /** * Get information about a specific organization */ async getOrganization(orgname: string): Promise { const response = await this.client.get(`/orgs/${orgname}`); return response.data; } /** * Update an organization */ async updateOrganization( orgname: string, data: { full_name?: string; description?: string; website?: string; location?: string; } ): Promise { const response = await this.client.patch(`/orgs/${orgname}`, data); return response.data; } /** * Add or update organization membership */ async addOrganizationMember( orgname: string, username: string, role: 'admin' | 'member' ): Promise { await this.client.put(`/orgs/${orgname}/memberships/${username}`, { role }); } /** * List teams in an organization */ async listOrganizationTeams(orgname: string): Promise { const response = await this.client.get(`/orgs/${orgname}/teams`); return response.data; } /** * Create a new team in an organization */ async createTeam( orgname: string, data: { name: string; description?: string; permission?: 'read' | 'write' | 'admin'; } ): Promise { const response = await this.client.post( `/admin/orgs/${orgname}/teams`, data ); return response.data; } /** * Get a specific team by ID */ async getTeam(teamId: number): Promise { const response = await this.client.get(`/teams/${teamId}`); return response.data; } /** * Add a user to a team */ async addTeamMember(teamId: number, username: string): Promise { await this.client.put(`/admin/teams/${teamId}/members/${username}`); } /** * Remove a user from a team */ async removeTeamMember(teamId: number, username: string): Promise { await this.client.delete(`/admin/teams/${teamId}/members/${username}`); } /** * List releases for a repository */ async listReleases(owner: string, repo: string): Promise { const response = await this.client.get(`/repos/${owner}/${repo}/releases`); return response.data; } /** * List collaborators for a repository */ async listCollaborators(owner: string, repo: string): Promise { const response = await this.client.get( `/repos/${owner}/${repo}/collaborators` ); return response.data; } /** * Check if a user is a collaborator */ async checkCollaborator(owner: string, repo: string, username: string): Promise { try { await this.client.get(`/repos/${owner}/${repo}/collaborators/${username}`); return true; } catch (error) { if (axios.isAxiosError(error) && error.response?.status === 404) { return false; } throw error; } } /** * Add a collaborator to a repository */ async addCollaborator( owner: string, repo: string, username: string, permission?: 'read' | 'write' | 'admin' ): Promise { await this.client.put(`/repos/${owner}/${repo}/collaborators/${username}`, { permission: permission || 'write', }); } /** * Remove a collaborator from a repository */ async removeCollaborator(owner: string, repo: string, username: string): Promise { await this.client.delete(`/repos/${owner}/${repo}/collaborators/${username}`); } /** * List email addresses for the authenticated user */ async listUserEmails(): Promise { const response = await this.client.get('/user/emails'); return response.data; } /** * Add email address(es) to the authenticated user's account */ async addUserEmails(emails: string[]): Promise { const response = await this.client.post('/user/emails', { emails }); return response.data; } /** * Delete email address(es) from the authenticated user's account */ async deleteUserEmails(emails: string[]): Promise { await this.client.delete('/user/emails', { data: { emails } }); } /** * List public keys for a specific user */ async listUserKeys(username: string): Promise { const response = await this.client.get(`/users/${username}/keys`); return response.data; } /** * List public keys for the authenticated user */ async listMyKeys(): Promise { const response = await this.client.get('/user/keys'); return response.data; } /** * Get a single public key by ID */ async getPublicKey(keyId: number): Promise { const response = await this.client.get(`/user/keys/${keyId}`); return response.data; } /** * Create a new public key for the authenticated user */ async createPublicKey(data: { title: string; key: string; }): Promise { const response = await this.client.post('/user/keys', data); return response.data; } /** * Delete a public key by ID */ async deletePublicKey(keyId: number): Promise { await this.client.delete(`/user/keys/${keyId}`); } /** * List webhooks for a repository */ async listHooks(owner: string, repo: string): Promise { const response = await this.client.get(`/repos/${owner}/${repo}/hooks`); return response.data; } /** * Create a new webhook for a repository */ async createHook( owner: string, repo: string, data: { type: GogsWebhookType; config: GogsWebhookConfig; events?: GogsWebhookEvent[]; active?: boolean; } ): Promise { const response = await this.client.post( `/repos/${owner}/${repo}/hooks`, data ); return response.data; } /** * Update an existing webhook */ async updateHook( owner: string, repo: string, hookId: number, data: { config: GogsWebhookConfig; events?: GogsWebhookEvent[]; active?: boolean; } ): Promise { const response = await this.client.patch( `/repos/${owner}/${repo}/hooks/${hookId}`, data ); return response.data; } /** * Delete a webhook from a repository */ async deleteHook(owner: string, repo: string, hookId: number): Promise { await this.client.delete(`/repos/${owner}/${repo}/hooks/${hookId}`); } /** * List followers of a user */ async listFollowers(username: string): Promise { const response = await this.client.get(`/users/${username}/followers`); return response.data; } /** * List users that a user is following */ async listFollowing(username: string): Promise { const response = await this.client.get(`/users/${username}/following`); return response.data; } /** * Check if the authenticated user is following a target user */ async checkFollowing(username: string): Promise { try { await this.client.get(`/user/following/${username}`); return true; } catch (error) { if (axios.isAxiosError(error) && error.response?.status === 404) { return false; } throw error; } } /** * Follow a user (authenticated user follows the target user) */ async followUser(username: string): Promise { await this.client.put(`/user/following/${username}`); } /** * Unfollow a user (authenticated user unfollows the target user) */ async unfollowUser(username: string): Promise { await this.client.delete(`/user/following/${username}`); } }