mirror of
https://github.com/actions/stale.git
synced 2025-12-27 10:48:18 +00:00
Add state
This commit is contained in:
@@ -17,6 +17,8 @@ export class ExemptDraftPullRequest {
|
||||
}
|
||||
|
||||
async shouldExemptDraftPullRequest(
|
||||
// keep this for backward compatibility
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
pullRequestCallback: () => Promise<IPullRequest | undefined | void>
|
||||
): Promise<boolean> {
|
||||
if (this._issue.isPullRequest) {
|
||||
|
||||
@@ -71,6 +71,7 @@ describe('Issue', (): void => {
|
||||
number: 8,
|
||||
created_at: 'dummy-created-at',
|
||||
updated_at: 'dummy-updated-at',
|
||||
draft: false,
|
||||
labels: [
|
||||
{
|
||||
name: 'dummy-name'
|
||||
|
||||
@@ -34,7 +34,7 @@ export class Issue implements IIssue {
|
||||
this.number = issue.number;
|
||||
this.created_at = issue.created_at;
|
||||
this.updated_at = issue.updated_at;
|
||||
this.draft = issue.draft || false;
|
||||
this.draft = Boolean(issue.draft);
|
||||
this.labels = mapLabels(issue.labels);
|
||||
this.pull_request = issue.pull_request;
|
||||
this.state = issue.state;
|
||||
|
||||
@@ -26,6 +26,7 @@ import {Statistics} from './statistics';
|
||||
import {LoggerService} from '../services/logger.service';
|
||||
import {OctokitIssue} from '../interfaces/issue';
|
||||
import {retry} from '@octokit/plugin-retry';
|
||||
import {IState} from '../interfaces/state';
|
||||
|
||||
/***
|
||||
* Handle processing of issues for staleness/closure.
|
||||
@@ -72,9 +73,11 @@ export class IssuesProcessor {
|
||||
readonly addedCloseCommentIssues: Issue[] = [];
|
||||
readonly statistics: Statistics | undefined;
|
||||
private readonly _logger: Logger = new Logger();
|
||||
private readonly state: IState;
|
||||
|
||||
constructor(options: IIssuesProcessorOptions) {
|
||||
constructor(options: IIssuesProcessorOptions, state: IState) {
|
||||
this.options = options;
|
||||
this.state = state;
|
||||
this.client = getOctokit(this.options.repoToken, undefined, retry);
|
||||
this.operations = new StaleOperations(this.options);
|
||||
|
||||
@@ -110,6 +113,8 @@ export class IssuesProcessor {
|
||||
?.setOperationsCount(this.operations.getConsumedOperationsCount())
|
||||
.logStats();
|
||||
|
||||
this.state.reset();
|
||||
|
||||
return this.operations.getRemainingOperationsCount();
|
||||
} else {
|
||||
this._logger.info(
|
||||
@@ -196,6 +201,15 @@ export class IssuesProcessor {
|
||||
)}`
|
||||
);
|
||||
|
||||
if (this.state.isIssueProcessed(issue)) {
|
||||
issueLogger.info(
|
||||
' $$type skipped due being processed during the previous run'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.state.addIssueToProcessed(issue);
|
||||
|
||||
// calculate string based messages for this issue
|
||||
const staleMessage: string = issue.isPullRequest
|
||||
? this.options.stalePrMessage
|
||||
|
||||
69
src/classes/state.ts
Normal file
69
src/classes/state.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import {Issue} from './issue';
|
||||
import {IState} from '../interfaces/state';
|
||||
import os from 'os';
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import artifact from '@actions/artifact';
|
||||
|
||||
type IssueID = number;
|
||||
export class State implements IState {
|
||||
private processedIssuesIDs: Set<IssueID>;
|
||||
constructor() {
|
||||
this.processedIssuesIDs = new Set();
|
||||
}
|
||||
|
||||
isIssueProcessed(issue: Issue) {
|
||||
return this.processedIssuesIDs.has(issue.number);
|
||||
}
|
||||
|
||||
addIssueToProcessed(issue: Issue) {
|
||||
this.processedIssuesIDs.add(issue.number);
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.processedIssuesIDs.clear();
|
||||
}
|
||||
|
||||
private static readonly ARTIFACT_NAME = '_stale_state';
|
||||
async persist() {
|
||||
const serialized = Array.from(this.processedIssuesIDs).join('|');
|
||||
|
||||
const tmpDir = os.tmpdir();
|
||||
const file = crypto.randomBytes(8).readBigUInt64LE(0).toString();
|
||||
fs.writeFileSync(path.join(tmpDir, file), serialized);
|
||||
|
||||
const artifactClient = artifact.create();
|
||||
// TODO: handle errors
|
||||
await artifactClient.uploadArtifact(State.ARTIFACT_NAME, [file], tmpDir);
|
||||
}
|
||||
|
||||
async rehydrate() {
|
||||
this.reset();
|
||||
|
||||
const tmpDir = os.tmpdir();
|
||||
const artifactClient = artifact.create();
|
||||
const downloadResponse = await artifactClient.downloadArtifact(
|
||||
State.ARTIFACT_NAME,
|
||||
tmpDir
|
||||
);
|
||||
|
||||
const downloadedFiles = fs.readdirSync(downloadResponse.downloadPath);
|
||||
if (downloadedFiles.length === 0) {
|
||||
// TODO: handle error
|
||||
}
|
||||
const serialized = fs.readFileSync(
|
||||
path.join(downloadResponse.downloadPath, downloadedFiles[0]),
|
||||
{encoding: 'utf8'}
|
||||
);
|
||||
|
||||
if (serialized.length === 0) return;
|
||||
|
||||
const issueIDs = serialized
|
||||
.split('|')
|
||||
.map(parseInt)
|
||||
.filter(i => !isNaN(i));
|
||||
|
||||
this.processedIssuesIDs = new Set(issueIDs);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user