mirror of
https://gitea.com/Lydanne/issues-helper.git
synced 2025-08-20 02:35:58 +08:00
feat: add doCheckInactive
This commit is contained in:
@@ -1,15 +1,105 @@
|
||||
import { dealStringToArr } from 'actions-util';
|
||||
import dayjs from 'dayjs';
|
||||
import utc from 'dayjs/plugin/utc';
|
||||
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
|
||||
import * as core from '../core';
|
||||
import { TIssueState, TUpdateMode, TEmoji, TLockReasons } from '../types';
|
||||
import { ELockReasons } from '../shared';
|
||||
import { IIssueCoreEngine } from '../issue';
|
||||
import { IIssueCoreEngine, IListIssuesParams, TListIssuesResults } from '../issue';
|
||||
import {
|
||||
doAddLabels,
|
||||
doCreateComment,
|
||||
} from './base';
|
||||
|
||||
let ICE: IIssueCoreEngine;
|
||||
|
||||
export function initAdvancedICE(_ICE: IIssueCoreEngine) {
|
||||
ICE = _ICE;
|
||||
}
|
||||
|
||||
export async function doCheckInactive() {
|
||||
export async function doQueryIssues(state: TIssueState | 'all', creator?: string): Promise<TListIssuesResults> {
|
||||
const params = {
|
||||
state,
|
||||
} as IListIssuesParams;
|
||||
|
||||
const issueCreator = core.getInput('issue-creator');
|
||||
const issueAssignee = core.getInput('issue-assignee');
|
||||
const issueMentioned = core.getInput('issue-mentioned');
|
||||
issueCreator ? (params.creator = issueCreator) : null;
|
||||
issueAssignee ? (params.assignee = issueAssignee) : null;
|
||||
issueMentioned ? (params.mentioned = issueMentioned) : null;
|
||||
|
||||
const labels = core.getInput('labels');
|
||||
labels ? params.labels = labels : null;
|
||||
|
||||
creator? params.creator = creator : null;
|
||||
|
||||
const issuesList = await ICE.listIssues(params);
|
||||
const issues: TListIssuesResults = [];
|
||||
const issueNumbers: number[] = [];
|
||||
|
||||
if (issuesList.length) {
|
||||
const excludeLabels = core.getInput('exclude-labels') || '';
|
||||
const bodyIncludes = core.getInput('body-includes');
|
||||
const titleIncludes = core.getInput('title-includes');
|
||||
|
||||
const excludeLabelsArr = dealStringToArr(excludeLabels);
|
||||
issuesList.forEach(issue => {
|
||||
const bodyCheck = bodyIncludes ? issue.body.includes(bodyIncludes) : true;
|
||||
const titleCheck = titleIncludes ? issue.title.includes(titleIncludes) : true;
|
||||
/**
|
||||
* Note: GitHub's REST API v3 considers every pull request an issue, but not every issue is a pull request.
|
||||
* For this reason, "Issues" endpoints may return both issues and pull requests in the response.
|
||||
* You can identify pull requests by the pull_request key.
|
||||
*/
|
||||
if (bodyCheck && titleCheck && issue.pull_request === undefined) {
|
||||
if (excludeLabelsArr.length) {
|
||||
for (let i = 0; i < issue.labels.length; i += 1) {
|
||||
if (excludeLabelsArr.includes(issue.labels[i].name)) return;
|
||||
}
|
||||
}
|
||||
|
||||
const inactiveDay = core.getInput('inactive-day');
|
||||
if (inactiveDay) {
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(isSameOrBefore);
|
||||
|
||||
const lastTime = dayjs.utc().subtract(+inactiveDay, 'day');
|
||||
const updateTime = dayjs.utc(issue.updated_at);
|
||||
if (updateTime.isSameOrBefore(lastTime)) {
|
||||
issues.push(issue);
|
||||
issueNumbers.push(issue.number);
|
||||
}
|
||||
} else {
|
||||
issues.push(issue);
|
||||
issueNumbers.push(issue.number);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
core.info(`[doQueryIssues] issueNumbers is [${JSON.stringify(issueNumbers)}]`);
|
||||
return issues;
|
||||
}
|
||||
|
||||
export async function doCheckInactive(body: string, emoji?: string) {
|
||||
let issueState = core.getInput('issue-state');
|
||||
if (issueState !== 'all' && issueState !== 'closed') {
|
||||
issueState = 'open';
|
||||
}
|
||||
const issues = await doQueryIssues(issueState as TIssueState | 'all');
|
||||
if (issues.length) {
|
||||
const inactiveLabel = core.getInput('inactive-label') || 'inactive';
|
||||
for (const issue of issues) {
|
||||
const { labels, number } = issue;
|
||||
const labelNames = labels.map(({name}) => name);
|
||||
if (!labelNames.includes(inactiveLabel)) {
|
||||
await doAddLabels([inactiveLabel], number);
|
||||
if (body) await doCreateComment(body, emoji, number);
|
||||
} else {
|
||||
core.info(`[doCheckInactive] The issue ${number} already has ${inactiveLabel} label!`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
core.info(`[doCheckInactive] Query issues empty!`);
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import { ELockReasons } from '../shared';
|
||||
import { IIssueCoreEngine } from '../issue';
|
||||
|
||||
let ICE: IIssueCoreEngine;
|
||||
|
||||
export function initBaseICE(_ICE: IIssueCoreEngine) {
|
||||
ICE = _ICE;
|
||||
}
|
||||
@@ -15,7 +14,8 @@ export async function doAddAssignees(assignees: string[]) {
|
||||
core.info(`[doAddAssignees] [${assignees}] success!`);
|
||||
}
|
||||
|
||||
export async function doAddLabels(labels: string[]) {
|
||||
export async function doAddLabels(labels: string[], issueNumber?: number) {
|
||||
if (issueNumber) ICE.setIssueNumber(issueNumber);
|
||||
await ICE.addLabels(labels);
|
||||
core.info(`[doAddLabels] [${labels}] success!`);
|
||||
}
|
||||
@@ -25,8 +25,9 @@ export async function doCloseIssue(issueNumber: number) {
|
||||
core.info(`[doCloseIssue] [${issueNumber}] success!`);
|
||||
}
|
||||
|
||||
export async function doCreateComment(body: string, emoji?: string) {
|
||||
export async function doCreateComment(body: string, emoji?: string, issueNumber?: number) {
|
||||
if (body) {
|
||||
if (issueNumber) ICE.setIssueNumber(issueNumber);
|
||||
const commentId = await ICE.createComment(body);
|
||||
core.info(`[doCreateComment] [${body}] success!`);
|
||||
core.setOutput('comment-id', commentId);
|
||||
@@ -127,6 +128,9 @@ export async function doUpdateComment(_commentId: number | void, body: string, u
|
||||
if (commentId) {
|
||||
await ICE.updateComment(+commentId, body, updateMode);
|
||||
core.info(`[doUpdateComment] [${commentId}] success!`);
|
||||
if (emoji) {
|
||||
await doCreateCommentEmoji(+commentId, emoji);
|
||||
}
|
||||
} else {
|
||||
core.warning(`[doUpdateComment] commentId is empty!`);
|
||||
}
|
||||
|
@@ -193,7 +193,7 @@ export class IssueHelperEngine implements IIssueHelperEngine {
|
||||
// ^_^ ============= ^_^
|
||||
// -[ Advanced Begin ]->
|
||||
case 'check-inactive': {
|
||||
await doCheckInactive();
|
||||
await doCheckInactive(body, emoji);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Octokit } from '@octokit/rest';
|
||||
|
||||
import { TEmoji, TLockReasons, TUpdateMode, TIssueState } from '../types';
|
||||
import { IIssueBaseInfo, IIssueCoreEngine } from './types';
|
||||
import { IIssueBaseInfo, IIssueCoreEngine, IListIssuesParams, TListIssuesResults } from './types';
|
||||
|
||||
export class IssueCoreEngine implements IIssueCoreEngine {
|
||||
private owner!: string;
|
||||
@@ -124,6 +124,22 @@ export class IssueCoreEngine implements IIssueCoreEngine {
|
||||
});
|
||||
}
|
||||
|
||||
public async listIssues(params: IListIssuesParams, page = 1) {
|
||||
const { octokit, owner, repo } = this;
|
||||
const { data } = await octokit.issues.listForRepo({
|
||||
...params,
|
||||
owner,
|
||||
repo,
|
||||
per_page: 100,
|
||||
page,
|
||||
});
|
||||
let issues = [...data] as unknown as TListIssuesResults;
|
||||
if (issues.length >= 100) {
|
||||
issues = issues.concat(await this.listIssues(params, page + 1));
|
||||
}
|
||||
return issues;
|
||||
}
|
||||
|
||||
public async lockIssue(lockReason: TLockReasons) {
|
||||
const { owner, repo, octokit, issueNumber } = this;
|
||||
const params: any = {
|
||||
@@ -165,7 +181,7 @@ export class IssueCoreEngine implements IIssueCoreEngine {
|
||||
issue_number: issueNumber,
|
||||
});
|
||||
|
||||
const baseLabels = issue.data.labels.map(({ name }: any) => name);
|
||||
const baseLabels: string[] = issue.data.labels.map(({ name }: any) => name);
|
||||
const removeLabels = baseLabels.filter(name => labels.includes(name));
|
||||
|
||||
for (const label of removeLabels) {
|
||||
@@ -190,7 +206,7 @@ export class IssueCoreEngine implements IIssueCoreEngine {
|
||||
issue_number: issueNumber,
|
||||
});
|
||||
|
||||
const baseLabels = issue.data.labels.map(({ name }: any) => name);
|
||||
const baseLabels: string[] = issue.data.labels.map(({ name }: any) => name);
|
||||
const removeLabels = baseLabels.filter(name => !labels.includes(name));
|
||||
const addLabels = labels.filter(name => !baseLabels.includes(name));
|
||||
|
||||
@@ -257,12 +273,4 @@ export class IssueCoreEngine implements IIssueCoreEngine {
|
||||
assignees: assignees?.length ? assignees : baseAssignessName,
|
||||
});
|
||||
}
|
||||
|
||||
public async queryIssues() {
|
||||
|
||||
}
|
||||
|
||||
private async listIssues(params, page = 1) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -8,13 +8,26 @@ export interface IIssueBaseInfo {
|
||||
}
|
||||
|
||||
export interface IListIssuesParams {
|
||||
owner: string;
|
||||
repo: string;
|
||||
state: 'all' | 'open' | 'closed';
|
||||
|
||||
|
||||
state: TIssueState | 'all';
|
||||
creator?: string;
|
||||
assignee?: string;
|
||||
mentioned?: string;
|
||||
labels?: string;
|
||||
}
|
||||
|
||||
export type TListIssuesResult = {
|
||||
number: number;
|
||||
title: string;
|
||||
body: string;
|
||||
labels: {
|
||||
name: string;
|
||||
}[];
|
||||
updated_at: string;
|
||||
pull_request?: any;
|
||||
}
|
||||
|
||||
export type TListIssuesResults = TListIssuesResult[];
|
||||
|
||||
export interface IIssueCoreEngine {
|
||||
setIssueNumber(newIssueNumber: number): void;
|
||||
addAssignees(assignees: string[]): Promise<void>;
|
||||
@@ -40,6 +53,7 @@ export interface IIssueCoreEngine {
|
||||
|
||||
deleteComment(commentId: number): Promise<void>;
|
||||
|
||||
listIssues(params: IListIssuesParams): Promise<TListIssuesResults>;
|
||||
lockIssue(lockReason: TLockReasons): Promise<void>;
|
||||
|
||||
openIssue(): Promise<void>;
|
||||
|
Reference in New Issue
Block a user