repository-provider
Version:
abstract interface to git repository providers like github, bitbucket and gitlab
277 lines (244 loc) • 6.04 kB
JavaScript
import { optionJSON } from "./attribute-extras.mjs";
import { OwnedObject } from "./owned-object.mjs";
import { Branch } from "./branch.mjs";
import { Repository } from "./repository.mjs";
import { Review } from "./review.mjs";
import {
url_attribute,
state_attribute,
body_attribute,
title_attribute,
boolean_attribute,
empty_attribute
} from "./attributes.mjs";
/**
* Abstract pull request.
* {@link Repository#addPullRequest}
* @param {Branch} source merge source
* @param {Branch} owner merge target
* @param {string} name
* @param {Object} [options]
* @param {string} [options.title]
* @param {string} [options.state]
* @param {boolean} [options.merged]
* @param {boolean} [options.locked]
* @property {string} name
* @property {Branch} source
* @property {Branch} destination
* @property {string} [title]
* @property {string} [state]
* @property {boolean} [merged]
* @property {boolean} [locked]
* @property {string} url
*/
export class PullRequest extends OwnedObject {
static get addMethodName() {
return "_addPullRequest";
}
static get deleteMethodName() {
return "_deletePullRequest";
}
static get type() {
return "pull-request";
}
static get collectionName() {
return "pullRequests";
}
/**
* States to list pull request by default
* @return {Set<string>} states to list by default
*/
static defaultListStates = new Set(["OPEN"]);
/**
* possible states
* @enum {string}
*/
static states = new Set(["OPEN", "MERGED", "CLOSED"]);
/**
* All valid merge methods
* @return {Set<string>} valid merge methods.
* @enum {string}
*/
static validMergeMethods = new Set(/*["MERGE", "SQUASH", "REBASE"]*/);
/**
* List all pull request for a given repo.
* Result will be filtered by source branch, destination branch and states
* @param {Repository} repository
* @param {Object} [filter]
* @param {Branch?} [filter.source]
* @param {Branch?} [filter.destination]
* @param {Set<string>} [filter.states]
* @return {AsyncIterable<PullRequest>}
*/
static async *list(repository, filter) {}
/**
* Open a pull request
*
* @param {Branch} source
* @param {Branch} destination
* @param {Object} [options]
*/
static async open(source, destination, options) {
return new this(source, destination, "-1", options);
}
static get attributes() {
return {
...super.attributes,
body: body_attribute,
title: title_attribute,
url: url_attribute,
/**
* state of the pull request.
* - OPEN
* - MERGED
* - CLOSED
* @return {string}
*/
state: {
...state_attribute,
default: "OPEN",
values: this.states
},
/**
* Locked state of the pull request.
* @return {boolean}
*/
locked: boolean_attribute,
/**
* Merged state of the pull request.
* @return {boolean}
*/
merged: boolean_attribute,
/**
* Draft state of the pull request.
* @return {boolean}
*/
draft: boolean_attribute,
dry: boolean_attribute,
empty: empty_attribute
};
}
/** @type {Branch} */ source;
constructor(source, owner, name, options) {
let state = "OPEN";
super(owner, name, options, {
state: {
set(value) {
value = value.toUpperCase();
// @ts-ignore
if (this.constructor.attributes.state.values.has(value)) {
state = value;
} else throw new Error(`Invalid Pull Request state ${value}`);
},
get() {
return state;
}
},
merged: {
set(value) {
if (value) {
state = "MERGED";
}
},
get() {
return state === "MERGED";
}
}
});
this.source = source;
}
get destination() {
return this.owner;
}
/**
* Name of the PR together with the repository.
* @return {string} PR full name
*/
get fullName() {
return `${this.repository.fullName}/${this.name}`;
}
/**
* URL of the pull request.
* @return {string} url
*/
get url() {
return `${this.repository.url}/pull/${this.name}`;
}
get number() {
return this.name;
}
get dry() {
return false;
}
/**
* @return {Repository} destination repository
*/
get repository() {
return this.owner.repository;
}
/**
* Delete the pull request from the {@link Repository}.
* @see {@link Repository#deletePullRequest}
* @return {Promise}
*/
async delete() {
return this.owner.deletePullRequest(this.name);
}
/**
* Merge the pull request.
* @param {string} method
*/
async merge(method = "MERGE") {
method = method.toUpperCase();
// @ts-ignore
if (this.constructor.validMergeMethods.has(method)) {
// @ts-ignore
await this._merge(method);
this.merged = true;
} else {
throw new Error(`Merging with ${method} is not supported`);
}
}
/**
* Decline the pull request.
*/
async decline() {}
/**
* @return {AsyncIterable<Review>}
*/
async *reviews() {}
toString() {
return [
// @ts-ignore
[this.name, this.title],
["source", this.source?.identifier],
["destination", this.owner.identifier],
// @ts-ignore
...Object.entries(this.constructor.attributes)
.filter(
([k, v]) =>
!v.isKey &&
v.type !== "url" &&
k !== "title" &&
k !== "body" &&
this[k] !== undefined
)
.map(([k]) => [k, this[k]])
]
.map(([k, v]) => `${k}: ${v}`)
.join(", ");
}
toJSON() {
return optionJSON(this, {
source: this.source,
destination: this.owner
});
}
/**
* Short human readable identifier with provider and branch.
* @return {string}
*/
get identifier() {
return `${this.owner.identifier}[${this.name}]`;
}
}