/* * 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 GitHubVendorManager from './vendormgr'; import assert from 'assert'; import { GHMutation, GHMutationCreateIssueArgs } from './api-types'; export default class GitHubRepoManager implements RepoManager { vendorMgr: GitHubVendorManager; repo: Repo; repoId: string; constructor(vendorMgr: GitHubVendorManager, repoPath: string) { this.vendorMgr = vendorMgr; const mobj = /^([^/\s]+)\/([^/\s]+)$/.exec(repoPath); assert(mobj, 'invalid repo path'); const [, owner, repoName] = mobj; this.repo = { vendor: this.vendorMgr.vendor, owner: { type: ACTOR_TYPE.UNKNOWN, username: owner, vendor: this.vendorMgr.vendor, }, name: repoName, }; this.repoId = ''; } public async initialize() { const meta = await this.vendorMgr._doRequest( ` query Query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { id name owner { login __typename } } } `, { owner: this.repo.owner.username, name: this.repo.name, }, ); assert(meta.repository); assert(meta.repository.owner); this.repoId = meta.repository.id; this.repo.name = meta.repository.name; this.repo.owner.username = meta.repository.owner.login; // @ts-ignore graphql-codegen ignores built-in graphql values switch (meta.repository.owner.__typename) { case 'Organization': this.repo.owner.type = ACTOR_TYPE.ORG; break; case 'User': this.repo.owner.type = ACTOR_TYPE.USER; break; } return this; } public async getIssue(number: string): Promise { const resp = await this.vendorMgr._doRequest( ` query Query($owner: String!, $name: String!, $number: Int!) { repository(owner: $owner, name: $name) { issue(number: $number) { title body closed } } } `, { owner: this.repo.owner.username, name: this.repo.name, number: parseInt(number, 10), }, ); assert(resp.repository, 'no repository'); assert(resp.repository.issue, 'no issue'); const { issue } = resp.repository; return { id: number, content: issue.body, title: issue.title, repo: this.repo, state: issue.closed ? ISSUE_STATE.CLOSED : ISSUE_STATE.OPEN, }; } public async replicateIssue(issue: Issue) { const resp = await this.vendorMgr._doRequest( ` mutation ($input: CreateIssueInput!) { createIssue(input: $input) { issue { number title body closed } } } `, { input: { repositoryId: this.repoId, title: issue.title, body: issue.content, }, }, ); assert(resp.createIssue, 'creating issue failed'); assert(resp.createIssue.issue, 'creating issue failed'); const replicated = resp.createIssue.issue; return { id: replicated.number.toString(), content: replicated.body, title: replicated.title, repo: this.repo, state: replicated.closed ? ISSUE_STATE.CLOSED : ISSUE_STATE.OPEN, }; } public async getMergeRequest(number: string): Promise { const resp = await this.vendorMgr._doRequest( ` query Query($owner: String!, $name: String!, $number: Int!) { repository(owner: $owner, name: $name) { pullRequest(number: $number) { title body isDraft mergeable state } } } `, { owner: this.repo.owner.username, name: this.repo.name, number: parseInt(number, 10), }, ); assert(resp.repository, 'no repository'); assert(resp.repository.pullRequest, 'no pull request'); const { pullRequest } = resp.repository; return { id: number, content: pullRequest.body, title: pullRequest.title, repo: this.repo, state: { OPEN: MERGE_REQUEST_STATE.OPEN, CLOSED: MERGE_REQUEST_STATE.CLOSED, MERGED: MERGE_REQUEST_STATE.MERGED, }[pullRequest.state], mergability: { MERGEABLE: MERGE_REQUEST_MERGABILITY.MERGEABLE, CONFLICTING: MERGE_REQUEST_MERGABILITY.CONFLICTING, UNKNOWN: null, }[pullRequest.mergeable], isDraft: pullRequest.isDraft, }; } }