/* * Copycat. Copyright (C) 2020 selfisekai and other contributors. * * This is free software, and you are welcome to redistribute it * under the GNU General Public License 3.0 or later; see the LICENSE file for details, * or, if the file is unavailable, visit . */ import { RepoManager, Issue, Repo, ACTOR_TYPE, ISSUE_STATE, MergeRequest, MERGE_REQUEST_STATE, MERGE_REQUEST_MERGABILITY, } from '../../types'; import GitLabVendorManager from './vendormgr'; import assert from 'assert'; export default class GitHubRepoManager implements RepoManager { vendorMgr: GitLabVendorManager; repo: Repo; repoPath: string; constructor(vendorMgr: GitLabVendorManager, repoPath: string) { this.vendorMgr = vendorMgr; const mobj = /^([^/\s]+)\/([^\s]+)$/.exec(repoPath); assert(mobj, 'invalid repo path'); // "small path" may be just repository name // or the whole path except the top-level owner const [, owner, repoSmallPath] = mobj; this.repo = { vendor: this.vendorMgr.vendor, owner: { type: ACTOR_TYPE.UNKNOWN, username: owner, vendor: this.vendorMgr.vendor, }, name: repoSmallPath, }; this.repoPath = repoPath; } public async initialize() { let meta = await this.vendorMgr._doRequest( ` query ($path: ID!, $ownerStr: String!, $ownerID: ID!) { project(fullPath: $path) { path namespace { path } } group(fullPath: $ownerID) { id } user(username: $ownerStr) { id } } `, { path: this.repoPath, // there's no way to check if the namespace is a user or group, // so we check if there's anyone using that username // but one is a String, and one is an ID // and these types just don't overlap 🤷‍♀️ ownerStr: this.repo.owner.username, ownerID: this.repo.owner.username, }, ); assert(meta.project); assert(meta.group || meta.user); this.repo.owner.username = meta.project.path; if (meta.group) { this.repo.owner.type = ACTOR_TYPE.ORG; } else if (meta.user) { this.repo.owner.type = ACTOR_TYPE.USER; } return this; } public async getIssue(number: string): Promise { const resp = await this.vendorMgr._doRequest( ` query ($path: ID!, $id: String!) { project(fullPath: $path) { issue(iid: $id) { title description state } } } `, { path: this.repoPath, id: number, }, ); assert(resp.project, 'no project'); assert(resp.project.issue, 'no issue'); const { issue } = resp.project; return { id: number, content: issue.description || '', title: issue.title, repo: this.repo, state: { opened: ISSUE_STATE.OPEN, closed: ISSUE_STATE.CLOSED, locked: ISSUE_STATE.CLOSED, all: ISSUE_STATE.CLOSED, // today's fact: gitlab api is fucked up }[issue.state], }; } public async getMergeRequest(number: string): Promise { const resp = await this.vendorMgr._doRequest( ` query ($path: ID!, $id: String!) { project(fullPath: $path) { mergeRequest(iid: $id) { title description state mergeStatus workInProgress } } } `, { path: this.repoPath, id: number, }, ); assert(resp.project, 'no project'); assert(resp.project.mergeRequest, 'no merge request'); const { mergeRequest } = resp.project; return { id: number, content: mergeRequest.description || '', title: mergeRequest.title, repo: this.repo, state: { opened: MERGE_REQUEST_STATE.OPEN, closed: MERGE_REQUEST_STATE.CLOSED, merged: MERGE_REQUEST_STATE.MERGED, locked: MERGE_REQUEST_STATE.CLOSED, all: MERGE_REQUEST_STATE.CLOSED, // today's fact: gitlab api is fucked up }[mergeRequest.state], mergability: ({ can_be_merged: MERGE_REQUEST_MERGABILITY.MERGEABLE, cannot_be_merged: MERGE_REQUEST_MERGABILITY.CONFLICTING, } as { [key: string]: MERGE_REQUEST_MERGABILITY | undefined })[ mergeRequest.mergeStatus || '' ] || null, isDraft: mergeRequest.workInProgress, }; } }