mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Bump axios (#19283)
This commit is contained in:
@@ -1,6 +0,0 @@
|
||||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
@@ -1,96 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export interface GitHub {
|
||||
query(query: Query): AsyncIterableIterator<GitHubIssue[]>
|
||||
|
||||
hasWriteAccess(user: User): Promise<boolean>
|
||||
|
||||
repoHasLabel(label: string): Promise<boolean>
|
||||
createLabel(label: string, color: string, description: string): Promise<void>
|
||||
deleteLabel(label: string): Promise<void>
|
||||
|
||||
readConfig(path: string): Promise<any>
|
||||
|
||||
createIssue(owner: string, repo: string, title: string, body: string): Promise<void>
|
||||
|
||||
releaseContainsCommit(release: string, commit: string): Promise<boolean>
|
||||
}
|
||||
|
||||
export interface GitHubIssue extends GitHub {
|
||||
getIssue(): Promise<Issue>
|
||||
|
||||
postComment(body: string): Promise<void>
|
||||
deleteComment(id: number): Promise<void>
|
||||
getComments(last?: boolean): AsyncIterableIterator<Comment[]>
|
||||
|
||||
closeIssue(): Promise<void>
|
||||
lockIssue(): Promise<void>
|
||||
|
||||
setMilestone(milestoneId: number): Promise<void>
|
||||
|
||||
addLabel(label: string): Promise<void>
|
||||
removeLabel(label: string): Promise<void>
|
||||
|
||||
addAssignee(assignee: string): Promise<void>
|
||||
|
||||
getClosingInfo(): Promise<{ hash: string | undefined; timestamp: number } | undefined>
|
||||
}
|
||||
|
||||
type SortVar =
|
||||
| 'comments'
|
||||
| 'reactions'
|
||||
| 'reactions-+1'
|
||||
| 'reactions--1'
|
||||
| 'reactions-smile'
|
||||
| 'reactions-thinking_face'
|
||||
| 'reactions-heart'
|
||||
| 'reactions-tada'
|
||||
| 'interactions'
|
||||
| 'created'
|
||||
| 'updated'
|
||||
type SortOrder = 'asc' | 'desc'
|
||||
export type Reactions = {
|
||||
'+1': number
|
||||
'-1': number
|
||||
laugh: number
|
||||
hooray: number
|
||||
confused: number
|
||||
heart: number
|
||||
rocket: number
|
||||
eyes: number
|
||||
}
|
||||
|
||||
export interface User {
|
||||
name: string
|
||||
isGitHubApp?: boolean
|
||||
}
|
||||
export interface Comment {
|
||||
author: User
|
||||
body: string
|
||||
id: number
|
||||
timestamp: number
|
||||
}
|
||||
export interface Issue {
|
||||
author: User
|
||||
body: string
|
||||
title: string
|
||||
labels: string[]
|
||||
open: boolean
|
||||
locked: boolean
|
||||
number: number
|
||||
numComments: number
|
||||
reactions: Reactions
|
||||
milestoneId: number | null
|
||||
assignee?: string
|
||||
createdAt: number
|
||||
updatedAt: number
|
||||
closedAt?: number
|
||||
}
|
||||
export interface Query {
|
||||
q: string
|
||||
sort?: SortVar
|
||||
order?: SortOrder
|
||||
}
|
||||
@@ -1,293 +0,0 @@
|
||||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const core_1 = require("@actions/core");
|
||||
const github_1 = require("@actions/github");
|
||||
const child_process_1 = require("child_process");
|
||||
const utils_1 = require("../utils/utils");
|
||||
class OctoKit {
|
||||
constructor(token, params, options = { readonly: false }) {
|
||||
this.token = token;
|
||||
this.params = params;
|
||||
this.options = options;
|
||||
// when in readonly mode, record labels just-created so at to not throw unneccesary errors
|
||||
this.mockLabels = new Set();
|
||||
this.writeAccessCache = {};
|
||||
this.octokit = new github_1.GitHub(token);
|
||||
}
|
||||
async *query(query) {
|
||||
const q = query.q + ` repo:${this.params.owner}/${this.params.repo}`;
|
||||
console.log(`Querying for ${q}:`);
|
||||
const options = this.octokit.search.issuesAndPullRequests.endpoint.merge({
|
||||
...query,
|
||||
q,
|
||||
per_page: 100,
|
||||
headers: { Accept: 'application/vnd.github.squirrel-girl-preview+json' },
|
||||
});
|
||||
let pageNum = 0;
|
||||
const timeout = async () => {
|
||||
if (pageNum < 2) {
|
||||
/* pass */
|
||||
}
|
||||
else if (pageNum < 4) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||
}
|
||||
else {
|
||||
await new Promise((resolve) => setTimeout(resolve, 30000));
|
||||
}
|
||||
};
|
||||
for await (const pageResponse of this.octokit.paginate.iterator(options)) {
|
||||
await timeout();
|
||||
await utils_1.logRateLimit(this.token);
|
||||
const page = pageResponse.data;
|
||||
console.log(`Page ${++pageNum}: ${page.map(({ number }) => number).join(' ')}`);
|
||||
yield page.map((issue) => new OctoKitIssue(this.token, this.params, this.octokitIssueToIssue(issue)));
|
||||
}
|
||||
}
|
||||
async createIssue(owner, repo, title, body) {
|
||||
core_1.debug(`Creating issue \`${title}\` on ${owner}/${repo}`);
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.create({ owner, repo, title, body });
|
||||
}
|
||||
octokitIssueToIssue(issue) {
|
||||
var _a, _b, _c, _d, _e, _f;
|
||||
return {
|
||||
author: { name: issue.user.login, isGitHubApp: issue.user.type === 'Bot' },
|
||||
body: issue.body,
|
||||
number: issue.number,
|
||||
title: issue.title,
|
||||
labels: issue.labels.map((label) => label.name),
|
||||
open: issue.state === 'open',
|
||||
locked: issue.locked,
|
||||
numComments: issue.comments,
|
||||
reactions: issue.reactions,
|
||||
assignee: (_b = (_a = issue.assignee) === null || _a === void 0 ? void 0 : _a.login) !== null && _b !== void 0 ? _b : (_d = (_c = issue.assignees) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.login,
|
||||
milestoneId: (_f = (_e = issue.milestone) === null || _e === void 0 ? void 0 : _e.number) !== null && _f !== void 0 ? _f : null,
|
||||
createdAt: +new Date(issue.created_at),
|
||||
updatedAt: +new Date(issue.updated_at),
|
||||
closedAt: issue.closed_at ? +new Date(issue.closed_at) : undefined,
|
||||
};
|
||||
}
|
||||
async hasWriteAccess(user) {
|
||||
if (user.name in this.writeAccessCache) {
|
||||
core_1.debug('Got permissions from cache for ' + user);
|
||||
return this.writeAccessCache[user.name];
|
||||
}
|
||||
core_1.debug('Fetching permissions for ' + user);
|
||||
const permissions = (await this.octokit.repos.getCollaboratorPermissionLevel({
|
||||
...this.params,
|
||||
username: user.name,
|
||||
})).data.permission;
|
||||
return (this.writeAccessCache[user.name] = permissions === 'admin' || permissions === 'write');
|
||||
}
|
||||
async repoHasLabel(name) {
|
||||
try {
|
||||
await this.octokit.issues.getLabel({ ...this.params, name });
|
||||
return true;
|
||||
}
|
||||
catch (err) {
|
||||
if (err.status === 404) {
|
||||
return this.options.readonly && this.mockLabels.has(name);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
async createLabel(name, color, description) {
|
||||
core_1.debug('Creating label ' + name);
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.createLabel({ ...this.params, color, description, name });
|
||||
else
|
||||
this.mockLabels.add(name);
|
||||
}
|
||||
async deleteLabel(name) {
|
||||
core_1.debug('Deleting label ' + name);
|
||||
try {
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.deleteLabel({ ...this.params, name });
|
||||
}
|
||||
catch (err) {
|
||||
if (err.status === 404) {
|
||||
return;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
async readConfig(path) {
|
||||
core_1.debug('Reading config at ' + path);
|
||||
const repoPath = `.github/${path}.json`;
|
||||
const data = (await this.octokit.repos.getContents({ ...this.params, path: repoPath })).data;
|
||||
if ('type' in data && data.type === 'file') {
|
||||
if (data.encoding === 'base64' && data.content) {
|
||||
return JSON.parse(Buffer.from(data.content, 'base64').toString('utf-8'));
|
||||
}
|
||||
throw Error(`Could not read contents "${data.content}" in encoding "${data.encoding}"`);
|
||||
}
|
||||
throw Error('Found directory at config path when expecting file' + JSON.stringify(data));
|
||||
}
|
||||
async releaseContainsCommit(release, commit) {
|
||||
if (utils_1.getInput('commitReleasedDebuggingOverride')) {
|
||||
return true;
|
||||
}
|
||||
return new Promise((resolve, reject) => child_process_1.exec(`git -C ./repo merge-base --is-ancestor ${commit} ${release}`, (err) => !err || err.code === 1 ? resolve(!err) : reject(err)));
|
||||
}
|
||||
}
|
||||
exports.OctoKit = OctoKit;
|
||||
class OctoKitIssue extends OctoKit {
|
||||
constructor(token, params, issueData, options = { readonly: false }) {
|
||||
super(token, params, options);
|
||||
this.params = params;
|
||||
this.issueData = issueData;
|
||||
}
|
||||
async addAssignee(assignee) {
|
||||
core_1.debug('Adding assignee ' + assignee + ' to ' + this.issueData.number);
|
||||
if (!this.options.readonly) {
|
||||
await this.octokit.issues.addAssignees({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
assignees: [assignee],
|
||||
});
|
||||
}
|
||||
}
|
||||
async closeIssue() {
|
||||
core_1.debug('Closing issue ' + this.issueData.number);
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.update({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
state: 'closed',
|
||||
});
|
||||
}
|
||||
async lockIssue() {
|
||||
core_1.debug('Locking issue ' + this.issueData.number);
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.lock({ ...this.params, issue_number: this.issueData.number });
|
||||
}
|
||||
async getIssue() {
|
||||
if (isIssue(this.issueData)) {
|
||||
core_1.debug('Got issue data from query result ' + this.issueData.number);
|
||||
return this.issueData;
|
||||
}
|
||||
console.log('Fetching issue ' + this.issueData.number);
|
||||
const issue = (await this.octokit.issues.get({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
mediaType: { previews: ['squirrel-girl'] },
|
||||
})).data;
|
||||
return (this.issueData = this.octokitIssueToIssue(issue));
|
||||
}
|
||||
async postComment(body) {
|
||||
core_1.debug(`Posting comment ${body} on ${this.issueData.number}`);
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.createComment({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
body,
|
||||
});
|
||||
}
|
||||
async deleteComment(id) {
|
||||
core_1.debug(`Deleting comment ${id} on ${this.issueData.number}`);
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.deleteComment({
|
||||
owner: this.params.owner,
|
||||
repo: this.params.repo,
|
||||
comment_id: id,
|
||||
});
|
||||
}
|
||||
async setMilestone(milestoneId) {
|
||||
core_1.debug(`Setting milestone for ${this.issueData.number} to ${milestoneId}`);
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.update({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
milestone: milestoneId,
|
||||
});
|
||||
}
|
||||
async *getComments(last) {
|
||||
core_1.debug('Fetching comments for ' + this.issueData.number);
|
||||
const response = this.octokit.paginate.iterator(this.octokit.issues.listComments.endpoint.merge({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
per_page: 100,
|
||||
...(last ? { per_page: 1, page: (await this.getIssue()).numComments } : {}),
|
||||
}));
|
||||
for await (const page of response) {
|
||||
yield page.data.map((comment) => ({
|
||||
author: { name: comment.user.login, isGitHubApp: comment.user.type === 'Bot' },
|
||||
body: comment.body,
|
||||
id: comment.id,
|
||||
timestamp: +new Date(comment.created_at),
|
||||
}));
|
||||
}
|
||||
}
|
||||
async addLabel(name) {
|
||||
core_1.debug(`Adding label ${name} to ${this.issueData.number}`);
|
||||
if (!(await this.repoHasLabel(name))) {
|
||||
throw Error(`Action could not execute becuase label ${name} is not defined.`);
|
||||
}
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.addLabels({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
labels: [name],
|
||||
});
|
||||
}
|
||||
async removeLabel(name) {
|
||||
core_1.debug(`Removing label ${name} from ${this.issueData.number}`);
|
||||
try {
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.removeLabel({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
name,
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
if (err.status === 404) {
|
||||
console.log(`Label ${name} not found on issue`);
|
||||
return;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
async getClosingInfo() {
|
||||
var _a;
|
||||
if ((await this.getIssue()).open) {
|
||||
return;
|
||||
}
|
||||
const options = this.octokit.issues.listEventsForTimeline.endpoint.merge({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
});
|
||||
let closingCommit;
|
||||
for await (const event of this.octokit.paginate.iterator(options)) {
|
||||
const timelineEvents = event.data;
|
||||
for (const timelineEvent of timelineEvents) {
|
||||
if (timelineEvent.event === 'closed') {
|
||||
closingCommit = {
|
||||
hash: (_a = timelineEvent.commit_id) !== null && _a !== void 0 ? _a : undefined,
|
||||
timestamp: +new Date(timelineEvent.created_at),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(`Got ${closingCommit} as closing commit of ${this.issueData.number}`);
|
||||
return closingCommit;
|
||||
}
|
||||
}
|
||||
exports.OctoKitIssue = OctoKitIssue;
|
||||
function isIssue(object) {
|
||||
const isIssue = 'author' in object &&
|
||||
'body' in object &&
|
||||
'title' in object &&
|
||||
'labels' in object &&
|
||||
'open' in object &&
|
||||
'locked' in object &&
|
||||
'number' in object &&
|
||||
'numComments' in object &&
|
||||
'reactions' in object &&
|
||||
'milestoneId' in object;
|
||||
return isIssue;
|
||||
}
|
||||
@@ -1,336 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { debug } from '@actions/core'
|
||||
import { GitHub as GitHubAPI } from '@actions/github'
|
||||
import { Octokit } from '@octokit/rest'
|
||||
import { exec } from 'child_process'
|
||||
import { getInput, logRateLimit } from '../utils/utils'
|
||||
import { Comment, GitHub, GitHubIssue, Issue, Query, User } from './api'
|
||||
|
||||
export class OctoKit implements GitHub {
|
||||
protected octokit: GitHubAPI
|
||||
// when in readonly mode, record labels just-created so at to not throw unneccesary errors
|
||||
protected mockLabels: Set<string> = new Set()
|
||||
|
||||
constructor(
|
||||
private token: string,
|
||||
protected params: { repo: string; owner: string },
|
||||
protected options: { readonly: boolean } = { readonly: false },
|
||||
) {
|
||||
this.octokit = new GitHubAPI(token)
|
||||
}
|
||||
|
||||
async *query(query: Query): AsyncIterableIterator<GitHubIssue[]> {
|
||||
const q = query.q + ` repo:${this.params.owner}/${this.params.repo}`
|
||||
console.log(`Querying for ${q}:`)
|
||||
|
||||
const options = this.octokit.search.issuesAndPullRequests.endpoint.merge({
|
||||
...query,
|
||||
q,
|
||||
per_page: 100,
|
||||
headers: { Accept: 'application/vnd.github.squirrel-girl-preview+json' },
|
||||
})
|
||||
|
||||
let pageNum = 0
|
||||
|
||||
const timeout = async () => {
|
||||
if (pageNum < 2) {
|
||||
/* pass */
|
||||
} else if (pageNum < 4) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 3000))
|
||||
} else {
|
||||
await new Promise((resolve) => setTimeout(resolve, 30000))
|
||||
}
|
||||
}
|
||||
|
||||
for await (const pageResponse of this.octokit.paginate.iterator(options)) {
|
||||
await timeout()
|
||||
await logRateLimit(this.token)
|
||||
const page: Array<Octokit.SearchIssuesAndPullRequestsResponseItemsItem> = pageResponse.data
|
||||
console.log(`Page ${++pageNum}: ${page.map(({ number }) => number).join(' ')}`)
|
||||
yield page.map(
|
||||
(issue) => new OctoKitIssue(this.token, this.params, this.octokitIssueToIssue(issue)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async createIssue(owner: string, repo: string, title: string, body: string): Promise<void> {
|
||||
debug(`Creating issue \`${title}\` on ${owner}/${repo}`)
|
||||
if (!this.options.readonly) await this.octokit.issues.create({ owner, repo, title, body })
|
||||
}
|
||||
|
||||
protected octokitIssueToIssue(
|
||||
issue: Octokit.IssuesGetResponse | Octokit.SearchIssuesAndPullRequestsResponseItemsItem,
|
||||
): Issue {
|
||||
return {
|
||||
author: { name: issue.user.login, isGitHubApp: issue.user.type === 'Bot' },
|
||||
body: issue.body,
|
||||
number: issue.number,
|
||||
title: issue.title,
|
||||
labels: (issue.labels as Octokit.IssuesGetLabelResponse[]).map((label) => label.name),
|
||||
open: issue.state === 'open',
|
||||
locked: (issue as any).locked,
|
||||
numComments: issue.comments,
|
||||
reactions: (issue as any).reactions,
|
||||
assignee: issue.assignee?.login ?? (issue as any).assignees?.[0]?.login,
|
||||
milestoneId: issue.milestone?.number ?? null,
|
||||
createdAt: +new Date(issue.created_at),
|
||||
updatedAt: +new Date(issue.updated_at),
|
||||
closedAt: issue.closed_at ? +new Date((issue.closed_at as unknown) as string) : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
private writeAccessCache: Record<string, boolean> = {}
|
||||
async hasWriteAccess(user: User): Promise<boolean> {
|
||||
if (user.name in this.writeAccessCache) {
|
||||
debug('Got permissions from cache for ' + user)
|
||||
return this.writeAccessCache[user.name]
|
||||
}
|
||||
debug('Fetching permissions for ' + user)
|
||||
const permissions = (
|
||||
await this.octokit.repos.getCollaboratorPermissionLevel({
|
||||
...this.params,
|
||||
username: user.name,
|
||||
})
|
||||
).data.permission
|
||||
return (this.writeAccessCache[user.name] = permissions === 'admin' || permissions === 'write')
|
||||
}
|
||||
|
||||
async repoHasLabel(name: string): Promise<boolean> {
|
||||
try {
|
||||
await this.octokit.issues.getLabel({ ...this.params, name })
|
||||
return true
|
||||
} catch (err) {
|
||||
if (err.status === 404) {
|
||||
return this.options.readonly && this.mockLabels.has(name)
|
||||
}
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async createLabel(name: string, color: string, description: string): Promise<void> {
|
||||
debug('Creating label ' + name)
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.createLabel({ ...this.params, color, description, name })
|
||||
else this.mockLabels.add(name)
|
||||
}
|
||||
|
||||
async deleteLabel(name: string): Promise<void> {
|
||||
debug('Deleting label ' + name)
|
||||
try {
|
||||
if (!this.options.readonly) await this.octokit.issues.deleteLabel({ ...this.params, name })
|
||||
} catch (err) {
|
||||
if (err.status === 404) {
|
||||
return
|
||||
}
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async readConfig(path: string): Promise<any> {
|
||||
debug('Reading config at ' + path)
|
||||
const repoPath = `.github/${path}.json`
|
||||
const data = (await this.octokit.repos.getContents({ ...this.params, path: repoPath })).data
|
||||
|
||||
if ('type' in data && data.type === 'file') {
|
||||
if (data.encoding === 'base64' && data.content) {
|
||||
return JSON.parse(Buffer.from(data.content, 'base64').toString('utf-8'))
|
||||
}
|
||||
throw Error(`Could not read contents "${data.content}" in encoding "${data.encoding}"`)
|
||||
}
|
||||
throw Error('Found directory at config path when expecting file' + JSON.stringify(data))
|
||||
}
|
||||
|
||||
async releaseContainsCommit(release: string, commit: string): Promise<boolean> {
|
||||
if (getInput('commitReleasedDebuggingOverride')) {
|
||||
return true
|
||||
}
|
||||
return new Promise((resolve, reject) =>
|
||||
exec(`git -C ./repo merge-base --is-ancestor ${commit} ${release}`, (err) =>
|
||||
!err || err.code === 1 ? resolve(!err) : reject(err),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class OctoKitIssue extends OctoKit implements GitHubIssue {
|
||||
constructor(
|
||||
token: string,
|
||||
protected params: { repo: string; owner: string },
|
||||
private issueData: { number: number } | Issue,
|
||||
options: { readonly: boolean } = { readonly: false },
|
||||
) {
|
||||
super(token, params, options)
|
||||
}
|
||||
|
||||
async addAssignee(assignee: string): Promise<void> {
|
||||
debug('Adding assignee ' + assignee + ' to ' + this.issueData.number)
|
||||
if (!this.options.readonly) {
|
||||
await this.octokit.issues.addAssignees({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
assignees: [assignee],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async closeIssue(): Promise<void> {
|
||||
debug('Closing issue ' + this.issueData.number)
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.update({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
state: 'closed',
|
||||
})
|
||||
}
|
||||
|
||||
async lockIssue(): Promise<void> {
|
||||
debug('Locking issue ' + this.issueData.number)
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.lock({ ...this.params, issue_number: this.issueData.number })
|
||||
}
|
||||
|
||||
async getIssue(): Promise<Issue> {
|
||||
if (isIssue(this.issueData)) {
|
||||
debug('Got issue data from query result ' + this.issueData.number)
|
||||
return this.issueData
|
||||
}
|
||||
|
||||
console.log('Fetching issue ' + this.issueData.number)
|
||||
const issue = (
|
||||
await this.octokit.issues.get({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
mediaType: { previews: ['squirrel-girl'] },
|
||||
})
|
||||
).data
|
||||
return (this.issueData = this.octokitIssueToIssue(issue))
|
||||
}
|
||||
|
||||
async postComment(body: string): Promise<void> {
|
||||
debug(`Posting comment ${body} on ${this.issueData.number}`)
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.createComment({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
body,
|
||||
})
|
||||
}
|
||||
|
||||
async deleteComment(id: number): Promise<void> {
|
||||
debug(`Deleting comment ${id} on ${this.issueData.number}`)
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.deleteComment({
|
||||
owner: this.params.owner,
|
||||
repo: this.params.repo,
|
||||
comment_id: id,
|
||||
})
|
||||
}
|
||||
|
||||
async setMilestone(milestoneId: number) {
|
||||
debug(`Setting milestone for ${this.issueData.number} to ${milestoneId}`)
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.update({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
milestone: milestoneId,
|
||||
})
|
||||
}
|
||||
|
||||
async *getComments(last?: boolean): AsyncIterableIterator<Comment[]> {
|
||||
debug('Fetching comments for ' + this.issueData.number)
|
||||
|
||||
const response = this.octokit.paginate.iterator(
|
||||
this.octokit.issues.listComments.endpoint.merge({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
per_page: 100,
|
||||
...(last ? { per_page: 1, page: (await this.getIssue()).numComments } : {}),
|
||||
}),
|
||||
)
|
||||
|
||||
for await (const page of response) {
|
||||
yield (page.data as Octokit.IssuesListCommentsResponseItem[]).map((comment) => ({
|
||||
author: { name: comment.user.login, isGitHubApp: comment.user.type === 'Bot' },
|
||||
body: comment.body,
|
||||
id: comment.id,
|
||||
timestamp: +new Date(comment.created_at),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
async addLabel(name: string): Promise<void> {
|
||||
debug(`Adding label ${name} to ${this.issueData.number}`)
|
||||
if (!(await this.repoHasLabel(name))) {
|
||||
throw Error(`Action could not execute becuase label ${name} is not defined.`)
|
||||
}
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.addLabels({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
labels: [name],
|
||||
})
|
||||
}
|
||||
|
||||
async removeLabel(name: string): Promise<void> {
|
||||
debug(`Removing label ${name} from ${this.issueData.number}`)
|
||||
try {
|
||||
if (!this.options.readonly)
|
||||
await this.octokit.issues.removeLabel({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
name,
|
||||
})
|
||||
} catch (err) {
|
||||
if (err.status === 404) {
|
||||
console.log(`Label ${name} not found on issue`)
|
||||
return
|
||||
}
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async getClosingInfo(): Promise<{ hash: string | undefined; timestamp: number } | undefined> {
|
||||
if ((await this.getIssue()).open) {
|
||||
return
|
||||
}
|
||||
|
||||
const options = this.octokit.issues.listEventsForTimeline.endpoint.merge({
|
||||
...this.params,
|
||||
issue_number: this.issueData.number,
|
||||
})
|
||||
let closingCommit: { hash: string | undefined; timestamp: number } | undefined
|
||||
for await (const event of this.octokit.paginate.iterator(options)) {
|
||||
const timelineEvents = event.data as Octokit.IssuesListEventsForTimelineResponseItem[]
|
||||
for (const timelineEvent of timelineEvents) {
|
||||
if (timelineEvent.event === 'closed') {
|
||||
closingCommit = {
|
||||
hash: timelineEvent.commit_id ?? undefined,
|
||||
timestamp: +new Date(timelineEvent.created_at),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(`Got ${closingCommit} as closing commit of ${this.issueData.number}`)
|
||||
return closingCommit
|
||||
}
|
||||
}
|
||||
|
||||
function isIssue(object: any): object is Issue {
|
||||
const isIssue =
|
||||
'author' in object &&
|
||||
'body' in object &&
|
||||
'title' in object &&
|
||||
'labels' in object &&
|
||||
'open' in object &&
|
||||
'locked' in object &&
|
||||
'number' in object &&
|
||||
'numComments' in object &&
|
||||
'reactions' in object &&
|
||||
'milestoneId' in object
|
||||
|
||||
return isIssue
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
class Testbed {
|
||||
constructor(config) {
|
||||
var _a, _b, _c, _d, _e;
|
||||
this.config = {
|
||||
globalLabels: (_a = config === null || config === void 0 ? void 0 : config.globalLabels) !== null && _a !== void 0 ? _a : [],
|
||||
configs: (_b = config === null || config === void 0 ? void 0 : config.configs) !== null && _b !== void 0 ? _b : {},
|
||||
writers: (_c = config === null || config === void 0 ? void 0 : config.writers) !== null && _c !== void 0 ? _c : [],
|
||||
releasedCommits: (_d = config === null || config === void 0 ? void 0 : config.releasedCommits) !== null && _d !== void 0 ? _d : [],
|
||||
queryRunner: (_e = config === null || config === void 0 ? void 0 : config.queryRunner) !== null && _e !== void 0 ? _e : async function* () {
|
||||
yield [];
|
||||
},
|
||||
};
|
||||
}
|
||||
async *query(query) {
|
||||
for await (const page of this.config.queryRunner(query)) {
|
||||
yield page.map((issue) => issue instanceof TestbedIssue ? issue : new TestbedIssue(this.config, issue));
|
||||
}
|
||||
}
|
||||
async createIssue(_owner, _repo, _title, _body) {
|
||||
// pass...
|
||||
}
|
||||
async readConfig(path) {
|
||||
return JSON.parse(JSON.stringify(this.config.configs[path]));
|
||||
}
|
||||
async hasWriteAccess(user) {
|
||||
return this.config.writers.includes(user.name);
|
||||
}
|
||||
async repoHasLabel(label) {
|
||||
return this.config.globalLabels.includes(label);
|
||||
}
|
||||
async createLabel(label, _color, _description) {
|
||||
this.config.globalLabels.push(label);
|
||||
}
|
||||
async deleteLabel(labelToDelete) {
|
||||
this.config.globalLabels = this.config.globalLabels.filter((label) => label !== labelToDelete);
|
||||
}
|
||||
async releaseContainsCommit(_release, commit) {
|
||||
return this.config.releasedCommits.includes(commit);
|
||||
}
|
||||
}
|
||||
exports.Testbed = Testbed;
|
||||
class TestbedIssue extends Testbed {
|
||||
constructor(globalConfig, issueConfig) {
|
||||
var _a, _b, _c;
|
||||
super(globalConfig);
|
||||
issueConfig = issueConfig !== null && issueConfig !== void 0 ? issueConfig : {};
|
||||
issueConfig.comments = (_a = issueConfig === null || issueConfig === void 0 ? void 0 : issueConfig.comments) !== null && _a !== void 0 ? _a : [];
|
||||
issueConfig.labels = (_b = issueConfig === null || issueConfig === void 0 ? void 0 : issueConfig.labels) !== null && _b !== void 0 ? _b : [];
|
||||
issueConfig.issue = {
|
||||
author: { name: 'JacksonKearl' },
|
||||
body: 'issue body',
|
||||
locked: false,
|
||||
numComments: ((_c = issueConfig === null || issueConfig === void 0 ? void 0 : issueConfig.comments) === null || _c === void 0 ? void 0 : _c.length) || 0,
|
||||
number: 1,
|
||||
open: true,
|
||||
title: 'issue title',
|
||||
assignee: undefined,
|
||||
reactions: {
|
||||
'+1': 0,
|
||||
'-1': 0,
|
||||
confused: 0,
|
||||
eyes: 0,
|
||||
heart: 0,
|
||||
hooray: 0,
|
||||
laugh: 0,
|
||||
rocket: 0,
|
||||
},
|
||||
closedAt: undefined,
|
||||
createdAt: +new Date(),
|
||||
updatedAt: +new Date(),
|
||||
...issueConfig.issue,
|
||||
};
|
||||
this.issueConfig = issueConfig;
|
||||
}
|
||||
async addAssignee(assignee) {
|
||||
this.issueConfig.issue.assignee = assignee;
|
||||
}
|
||||
async setMilestone(milestoneId) {
|
||||
this.issueConfig.issue.milestoneId = milestoneId;
|
||||
}
|
||||
async getIssue() {
|
||||
const labels = [...this.issueConfig.labels];
|
||||
return { ...this.issueConfig.issue, labels };
|
||||
}
|
||||
async postComment(body, author) {
|
||||
this.issueConfig.comments.push({
|
||||
author: { name: author !== null && author !== void 0 ? author : 'bot' },
|
||||
body,
|
||||
id: Math.random(),
|
||||
timestamp: +new Date(),
|
||||
});
|
||||
}
|
||||
async deleteComment(id) {
|
||||
this.issueConfig.comments = this.issueConfig.comments.filter((comment) => comment.id !== id);
|
||||
}
|
||||
async *getComments(last) {
|
||||
yield last
|
||||
? [this.issueConfig.comments[this.issueConfig.comments.length - 1]]
|
||||
: this.issueConfig.comments;
|
||||
}
|
||||
async addLabel(label) {
|
||||
this.issueConfig.labels.push(label);
|
||||
}
|
||||
async removeLabel(labelToDelete) {
|
||||
this.issueConfig.labels = this.issueConfig.labels.filter((label) => label !== labelToDelete);
|
||||
}
|
||||
async closeIssue() {
|
||||
this.issueConfig.issue.open = false;
|
||||
}
|
||||
async lockIssue() {
|
||||
this.issueConfig.issue.locked = true;
|
||||
}
|
||||
async getClosingInfo() {
|
||||
return this.issueConfig.closingCommit;
|
||||
}
|
||||
}
|
||||
exports.TestbedIssue = TestbedIssue;
|
||||
@@ -1,170 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Comment, GitHub, GitHubIssue, Issue, Query, User } from './api'
|
||||
|
||||
type TestbedConfig = {
|
||||
globalLabels: string[]
|
||||
configs: Record<string, any>
|
||||
writers: string[]
|
||||
releasedCommits: string[]
|
||||
queryRunner: (query: Query) => AsyncIterableIterator<(TestbedIssueConstructorArgs | TestbedIssue)[]>
|
||||
}
|
||||
|
||||
export type TestbedConstructorArgs = Partial<TestbedConfig>
|
||||
|
||||
export class Testbed implements GitHub {
|
||||
public config: TestbedConfig
|
||||
|
||||
constructor(config?: TestbedConstructorArgs) {
|
||||
this.config = {
|
||||
globalLabels: config?.globalLabels ?? [],
|
||||
configs: config?.configs ?? {},
|
||||
writers: config?.writers ?? [],
|
||||
releasedCommits: config?.releasedCommits ?? [],
|
||||
queryRunner:
|
||||
config?.queryRunner ??
|
||||
async function* () {
|
||||
yield []
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async *query(query: Query): AsyncIterableIterator<GitHubIssue[]> {
|
||||
for await (const page of this.config.queryRunner(query)) {
|
||||
yield page.map((issue) =>
|
||||
issue instanceof TestbedIssue ? issue : new TestbedIssue(this.config, issue),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async createIssue(_owner: string, _repo: string, _title: string, _body: string): Promise<void> {
|
||||
// pass...
|
||||
}
|
||||
|
||||
async readConfig(path: string): Promise<any> {
|
||||
return JSON.parse(JSON.stringify(this.config.configs[path]))
|
||||
}
|
||||
|
||||
async hasWriteAccess(user: User): Promise<boolean> {
|
||||
return this.config.writers.includes(user.name)
|
||||
}
|
||||
|
||||
async repoHasLabel(label: string): Promise<boolean> {
|
||||
return this.config.globalLabels.includes(label)
|
||||
}
|
||||
|
||||
async createLabel(label: string, _color: string, _description: string): Promise<void> {
|
||||
this.config.globalLabels.push(label)
|
||||
}
|
||||
|
||||
async deleteLabel(labelToDelete: string): Promise<void> {
|
||||
this.config.globalLabels = this.config.globalLabels.filter((label) => label !== labelToDelete)
|
||||
}
|
||||
|
||||
async releaseContainsCommit(_release: string, commit: string): Promise<boolean> {
|
||||
return this.config.releasedCommits.includes(commit)
|
||||
}
|
||||
}
|
||||
|
||||
type TestbedIssueConfig = {
|
||||
issue: Omit<Issue, 'labels'>
|
||||
comments: Comment[]
|
||||
labels: string[]
|
||||
closingCommit: { hash: string | undefined; timestamp: number } | undefined
|
||||
}
|
||||
|
||||
export type TestbedIssueConstructorArgs = Partial<Omit<TestbedIssueConfig, 'issue'>> & {
|
||||
issue?: Partial<Omit<Issue, 'labels'>>
|
||||
}
|
||||
|
||||
export class TestbedIssue extends Testbed implements GitHubIssue {
|
||||
public issueConfig: TestbedIssueConfig
|
||||
|
||||
constructor(globalConfig?: TestbedConstructorArgs, issueConfig?: TestbedIssueConstructorArgs) {
|
||||
super(globalConfig)
|
||||
issueConfig = issueConfig ?? {}
|
||||
issueConfig.comments = issueConfig?.comments ?? []
|
||||
issueConfig.labels = issueConfig?.labels ?? []
|
||||
issueConfig.issue = {
|
||||
author: { name: 'JacksonKearl' },
|
||||
body: 'issue body',
|
||||
locked: false,
|
||||
numComments: issueConfig?.comments?.length || 0,
|
||||
number: 1,
|
||||
open: true,
|
||||
title: 'issue title',
|
||||
assignee: undefined,
|
||||
reactions: {
|
||||
'+1': 0,
|
||||
'-1': 0,
|
||||
confused: 0,
|
||||
eyes: 0,
|
||||
heart: 0,
|
||||
hooray: 0,
|
||||
laugh: 0,
|
||||
rocket: 0,
|
||||
},
|
||||
closedAt: undefined,
|
||||
createdAt: +new Date(),
|
||||
updatedAt: +new Date(),
|
||||
...issueConfig.issue,
|
||||
}
|
||||
|
||||
this.issueConfig = issueConfig as TestbedIssueConfig
|
||||
}
|
||||
|
||||
async addAssignee(assignee: string): Promise<void> {
|
||||
this.issueConfig.issue.assignee = assignee
|
||||
}
|
||||
|
||||
async setMilestone(milestoneId: number): Promise<void> {
|
||||
this.issueConfig.issue.milestoneId = milestoneId
|
||||
}
|
||||
|
||||
async getIssue(): Promise<Issue> {
|
||||
const labels = [...this.issueConfig.labels]
|
||||
return { ...this.issueConfig.issue, labels }
|
||||
}
|
||||
|
||||
async postComment(body: string, author?: string): Promise<void> {
|
||||
this.issueConfig.comments.push({
|
||||
author: { name: author ?? 'bot' },
|
||||
body,
|
||||
id: Math.random(),
|
||||
timestamp: +new Date(),
|
||||
})
|
||||
}
|
||||
|
||||
async deleteComment(id: number): Promise<void> {
|
||||
this.issueConfig.comments = this.issueConfig.comments.filter((comment) => comment.id !== id)
|
||||
}
|
||||
|
||||
async *getComments(last?: boolean): AsyncIterableIterator<Comment[]> {
|
||||
yield last
|
||||
? [this.issueConfig.comments[this.issueConfig.comments.length - 1]]
|
||||
: this.issueConfig.comments
|
||||
}
|
||||
|
||||
async addLabel(label: string): Promise<void> {
|
||||
this.issueConfig.labels.push(label)
|
||||
}
|
||||
|
||||
async removeLabel(labelToDelete: string): Promise<void> {
|
||||
this.issueConfig.labels = this.issueConfig.labels.filter((label) => label !== labelToDelete)
|
||||
}
|
||||
|
||||
async closeIssue(): Promise<void> {
|
||||
this.issueConfig.issue.open = false
|
||||
}
|
||||
|
||||
async lockIssue(): Promise<void> {
|
||||
this.issueConfig.issue.locked = true
|
||||
}
|
||||
|
||||
async getClosingInfo(): Promise<{ hash: string | undefined; timestamp: number } | undefined> {
|
||||
return this.issueConfig.closingCommit
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user