feat(remove-stale-when-updated): add 2 options for issues and prs (#383)
* docs(only-labels): enhance the docs and fix duplicate (#341) * docs(only-labels): remove duplicated option and improve descriptions a bad rebase happend * docs(readme): use a multi-line array and remove the optional column the option column was not helpful since each value is optional the multi-line array will allow to have a better UI in small devices and basically in GitHub too due to the max-width * style(readme): break line for the statistics * docs(readme): add a better description for the ascending option * docs(action): add missing punctuation * build(deps-dev): bump @typescript-eslint/eslint-plugin (#342) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 4.15.2 to 4.16.1. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.16.1/packages/eslint-plugin) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @octokit/rest from 18.3.0 to 18.3.2 (#350) Bumps [@octokit/rest](https://github.com/octokit/rest.js) from 18.3.0 to 18.3.2. - [Release notes](https://github.com/octokit/rest.js/releases) - [Commits](https://github.com/octokit/rest.js/compare/v18.3.0...v18.3.2) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * test: add more coverage for the stale label behaviour (#352) (#15) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * test: add more coverage for the stale label behaviour (#352) (#17) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * test: add more coverage for the stale label behaviour (#352) (#18) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat(remove-stale-when-updated): add 2 options for issues and prs closes #377 also I closed the stale process once the stale label is removed since the following process is regarding the closing and it should simply not occur if no longer stale * chore(logs): add more logs to understand the process * chore(logs): highlights more logs and humanize a bit more * chore(index): update it * refactor(checks): simplify if complexity Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
parent
043fbbdea3
commit
440fb174b5
|
@ -9,7 +9,7 @@ Warns and then closes issues and PRs that have had no activity for a specified a
|
||||||
Every argument is optional.
|
Every argument is optional.
|
||||||
|
|
||||||
| Input | Description |
|
| Input | Description |
|
||||||
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `repo-token` | PAT(Personal Access Token) for authorizing repository.<br>_Defaults to **${{ github.token }}**_. |
|
| `repo-token` | PAT(Personal Access Token) for authorizing repository.<br>_Defaults to **${{ github.token }}**_. |
|
||||||
| `days-before-stale` | Idle number of days before marking an issue/PR as stale.<br>_Defaults to **60**_. |
|
| `days-before-stale` | Idle number of days before marking an issue/PR as stale.<br>_Defaults to **60**_. |
|
||||||
| `days-before-issue-stale` | Idle number of days before marking an issue as stale.<br>_Override `days-before-stale`_. |
|
| `days-before-issue-stale` | Idle number of days before marking an issue as stale.<br>_Override `days-before-stale`_. |
|
||||||
|
@ -35,6 +35,8 @@ Every argument is optional.
|
||||||
| `any-of-pr-labels` | Only PRs with ANY of these labels are checked.<br>Separate multiple labels with commas (eg. "incomplete,waiting-feedback").<br>_Override `any-of-labels`_. |
|
| `any-of-pr-labels` | Only PRs with ANY of these labels are checked.<br>Separate multiple labels with commas (eg. "incomplete,waiting-feedback").<br>_Override `any-of-labels`_. |
|
||||||
| `operations-per-run` | Maximum number of operations per run.<br>GitHub API CRUD related.<br>_Defaults to **30**_. |
|
| `operations-per-run` | Maximum number of operations per run.<br>GitHub API CRUD related.<br>_Defaults to **30**_. |
|
||||||
| `remove-stale-when-updated` | Remove stale label from issue/PR on updates or comments.<br>_Defaults to **true**_. |
|
| `remove-stale-when-updated` | Remove stale label from issue/PR on updates or comments.<br>_Defaults to **true**_. |
|
||||||
|
| `remove-issue-stale-when-updated` | Remove stale label from issue on updates or comments.<br>_Defaults to **true**_.<br>_Override `remove-stale-when-updated`_. |
|
||||||
|
| `remove-pr-stale-when-updated` | Remove stale label from PR on updates or comments.<br>_Defaults to **true**_.<br>_Override `remove-stale-when-updated`_. |
|
||||||
| `debug-only` | Dry-run on action.<br>_Defaults to **false**_. |
|
| `debug-only` | Dry-run on action.<br>_Defaults to **false**_. |
|
||||||
| `ascending` | Order to get issues/PR.<br>`true` is ascending, `false` is descending.<br>_Defaults to **false**_. |
|
| `ascending` | Order to get issues/PR.<br>`true` is ascending, `false` is descending.<br>_Defaults to **false**_. |
|
||||||
| `skip-stale-issue-message` | Skip adding stale message on stale issue.<br>_Defaults to **false**_. |
|
| `skip-stale-issue-message` | Skip adding stale message on stale issue.<br>_Defaults to **false**_. |
|
||||||
|
|
|
@ -27,6 +27,8 @@ export const DefaultProcessorOptions: IIssuesProcessorOptions = Object.freeze({
|
||||||
operationsPerRun: 100,
|
operationsPerRun: 100,
|
||||||
debugOnly: true,
|
debugOnly: true,
|
||||||
removeStaleWhenUpdated: false,
|
removeStaleWhenUpdated: false,
|
||||||
|
removeIssueStaleWhenUpdated: undefined,
|
||||||
|
removePrStaleWhenUpdated: undefined,
|
||||||
ascending: false,
|
ascending: false,
|
||||||
skipStaleIssueMessage: false,
|
skipStaleIssueMessage: false,
|
||||||
skipStalePrMessage: false,
|
skipStalePrMessage: false,
|
||||||
|
|
|
@ -1220,8 +1220,7 @@ test('stale issues should not be closed if days is set to -1', async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('stale label should be removed if a comment was added to a stale issue', async () => {
|
test('stale label should be removed if a comment was added to a stale issue', async () => {
|
||||||
const opts = {...DefaultProcessorOptions};
|
const opts = {...DefaultProcessorOptions, removeStaleWhenUpdated: true};
|
||||||
opts.removeStaleWhenUpdated = true;
|
|
||||||
const TestIssueList: Issue[] = [
|
const TestIssueList: Issue[] = [
|
||||||
generateIssue(
|
generateIssue(
|
||||||
opts,
|
opts,
|
||||||
|
@ -1257,8 +1256,7 @@ test('stale label should be removed if a comment was added to a stale issue', as
|
||||||
});
|
});
|
||||||
|
|
||||||
test('stale label should not be removed if a comment was added by the bot (and the issue should be closed)', async () => {
|
test('stale label should not be removed if a comment was added by the bot (and the issue should be closed)', async () => {
|
||||||
const opts = {...DefaultProcessorOptions};
|
const opts = {...DefaultProcessorOptions, removeStaleWhenUpdated: true};
|
||||||
opts.removeStaleWhenUpdated = true;
|
|
||||||
github.context.actor = 'abot';
|
github.context.actor = 'abot';
|
||||||
const TestIssueList: Issue[] = [
|
const TestIssueList: Issue[] = [
|
||||||
generateIssue(
|
generateIssue(
|
||||||
|
|
|
@ -0,0 +1,567 @@
|
||||||
|
import {Issue} from '../src/classes/issue';
|
||||||
|
import {IIssue} from '../src/interfaces/issue';
|
||||||
|
import {IIssuesProcessorOptions} from '../src/interfaces/issues-processor-options';
|
||||||
|
import {ILabel} from '../src/interfaces/label';
|
||||||
|
import {IssuesProcessorMock} from './classes/issues-processor-mock';
|
||||||
|
import {DefaultProcessorOptions} from './constants/default-processor-options';
|
||||||
|
import {generateIssue} from './functions/generate-issue';
|
||||||
|
|
||||||
|
let issuesProcessorBuilder: IssuesProcessorBuilder;
|
||||||
|
let issuesProcessor: IssuesProcessorMock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description
|
||||||
|
* Assuming there is a comment on the issue
|
||||||
|
*/
|
||||||
|
describe('remove-stale-when-updated option', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder = new IssuesProcessorBuilder();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-stale-when-updated" is disabled', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.keepStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not remove the stale label on the issue', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.staleIssues([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not remove the stale label on the pull request', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.stalePrs([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-stale-when-updated" is enabled', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.removeStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove the stale label on the issue', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.staleIssues([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove the stale label on the pull request', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.stalePrs([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('remove-issue-stale-when-updated option', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder = new IssuesProcessorBuilder();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-stale-when-updated" is disabled', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.keepStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-issue-stale-when-updated" is unset', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.unsetIssueStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not remove the stale label on the issue', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.staleIssues([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not remove the stale label on the pull request', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.stalePrs([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-issue-stale-when-updated" is disabled', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.keepIssueStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not remove the stale label on the issue', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.staleIssues([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not remove the stale label on the pull request', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.stalePrs([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-issue-stale-when-updated" is enabled', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.removeIssueStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove the stale label on the issue', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.staleIssues([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not remove the stale label on the pull request', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.stalePrs([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-stale-when-updated" is enabled', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.removeStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-issue-stale-when-updated" is unset', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.unsetIssueStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove the stale label on the issue', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.staleIssues([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove the stale label on the pull request', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.stalePrs([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-issue-stale-when-updated" is disabled', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.keepIssueStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not remove the stale label on the issue', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.staleIssues([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove the stale label on the pull request', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.stalePrs([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-issue-stale-when-updated" is enabled', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.removeIssueStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove the stale label on the issue', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.staleIssues([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove the stale label on the pull request', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.stalePrs([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('remove-pr-stale-when-updated option', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder = new IssuesProcessorBuilder();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-stale-when-updated" is disabled', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.keepStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-pr-stale-when-updated" is unset', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.unsetPrStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not remove the stale label on the issue', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.staleIssues([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not remove the stale label on the pull request', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.stalePrs([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-pr-stale-when-updated" is disabled', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.keepPrStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not remove the stale label on the issue', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.staleIssues([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not remove the stale label on the pull request', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.stalePrs([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-pr-stale-when-updated" is enabled', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.removePrStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not remove the stale label on the issue', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.staleIssues([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove the stale label on the pull request', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.stalePrs([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-stale-when-updated" is enabled', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.removeStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-pr-stale-when-updated" is unset', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.unsetPrStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove the stale label on the issue', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.staleIssues([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove the stale label on the pull request', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.stalePrs([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-pr-stale-when-updated" is disabled', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.keepPrStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove the stale label on the issue', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.staleIssues([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not remove the stale label on the pull request', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.stalePrs([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the option "remove-pr-stale-when-updated" is enabled', (): void => {
|
||||||
|
beforeEach((): void => {
|
||||||
|
issuesProcessorBuilder.removePrStaleWhenUpdated();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove the stale label on the issue', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.staleIssues([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should remove the stale label on the pull request', async (): Promise<void> => {
|
||||||
|
expect.assertions(1);
|
||||||
|
issuesProcessor = issuesProcessorBuilder.stalePrs([{}]).build();
|
||||||
|
|
||||||
|
await issuesProcessor.processIssues();
|
||||||
|
|
||||||
|
expect(issuesProcessor.removedLabelIssues).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
class IssuesProcessorBuilder {
|
||||||
|
private _options: IIssuesProcessorOptions = {
|
||||||
|
...DefaultProcessorOptions
|
||||||
|
};
|
||||||
|
private _issues: Issue[] = [];
|
||||||
|
|
||||||
|
keepStaleWhenUpdated(): IssuesProcessorBuilder {
|
||||||
|
this._options.removeStaleWhenUpdated = false;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeStaleWhenUpdated(): IssuesProcessorBuilder {
|
||||||
|
this._options.removeStaleWhenUpdated = true;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsetIssueStaleWhenUpdated(): IssuesProcessorBuilder {
|
||||||
|
delete this._options.removeIssueStaleWhenUpdated;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
keepIssueStaleWhenUpdated(): IssuesProcessorBuilder {
|
||||||
|
this._options.removeIssueStaleWhenUpdated = false;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeIssueStaleWhenUpdated(): IssuesProcessorBuilder {
|
||||||
|
this._options.removeIssueStaleWhenUpdated = true;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsetPrStaleWhenUpdated(): IssuesProcessorBuilder {
|
||||||
|
delete this._options.removePrStaleWhenUpdated;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
keepPrStaleWhenUpdated(): IssuesProcessorBuilder {
|
||||||
|
this._options.removePrStaleWhenUpdated = false;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
removePrStaleWhenUpdated(): IssuesProcessorBuilder {
|
||||||
|
this._options.removePrStaleWhenUpdated = true;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
issuesOrPrs(issues: Partial<IIssue>[]): IssuesProcessorBuilder {
|
||||||
|
this._issues = issues.map(
|
||||||
|
(issue: Readonly<Partial<IIssue>>, index: Readonly<number>): Issue =>
|
||||||
|
generateIssue(
|
||||||
|
this._options,
|
||||||
|
index,
|
||||||
|
issue.title ?? 'dummy-title',
|
||||||
|
issue.updated_at ?? new Date().toDateString(),
|
||||||
|
issue.created_at ?? new Date().toDateString(),
|
||||||
|
!!issue.pull_request,
|
||||||
|
issue.labels ? issue.labels.map(label => label.name) : []
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
issues(issues: Partial<IIssue>[]): IssuesProcessorBuilder {
|
||||||
|
this.issuesOrPrs(
|
||||||
|
issues.map(
|
||||||
|
(issue: Readonly<Partial<IIssue>>): Partial<IIssue> => {
|
||||||
|
return {
|
||||||
|
...issue,
|
||||||
|
pull_request: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
staleIssues(issues: Partial<IIssue>[]): IssuesProcessorBuilder {
|
||||||
|
this.issues(
|
||||||
|
issues.map(
|
||||||
|
(issue: Readonly<Partial<IIssue>>): Partial<IIssue> => {
|
||||||
|
return {
|
||||||
|
...issue,
|
||||||
|
updated_at: '2020-01-01T17:00:00Z',
|
||||||
|
created_at: '2020-01-01T17:00:00Z',
|
||||||
|
labels: issue.labels?.map(
|
||||||
|
(label: Readonly<ILabel>): ILabel => {
|
||||||
|
return {
|
||||||
|
...label,
|
||||||
|
name: 'Stale'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
) ?? [
|
||||||
|
{
|
||||||
|
name: 'Stale'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
prs(issues: Partial<IIssue>[]): IssuesProcessorBuilder {
|
||||||
|
this.issuesOrPrs(
|
||||||
|
issues.map(
|
||||||
|
(issue: Readonly<Partial<IIssue>>): Partial<IIssue> => {
|
||||||
|
return {
|
||||||
|
...issue,
|
||||||
|
pull_request: {key: 'value'}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
stalePrs(issues: Partial<IIssue>[]): IssuesProcessorBuilder {
|
||||||
|
this.prs(
|
||||||
|
issues.map(
|
||||||
|
(issue: Readonly<Partial<IIssue>>): Partial<IIssue> => {
|
||||||
|
return {
|
||||||
|
...issue,
|
||||||
|
updated_at: '2020-01-01T17:00:00Z',
|
||||||
|
created_at: '2020-01-01T17:00:00Z',
|
||||||
|
labels: issue.labels?.map(
|
||||||
|
(label: Readonly<ILabel>): ILabel => {
|
||||||
|
return {
|
||||||
|
...label,
|
||||||
|
name: 'Stale'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
) ?? [
|
||||||
|
{
|
||||||
|
name: 'Stale'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
build(): IssuesProcessorMock {
|
||||||
|
return new IssuesProcessorMock(
|
||||||
|
this._options,
|
||||||
|
async () => 'abot',
|
||||||
|
async p => (p === 1 ? this._issues : []),
|
||||||
|
async () => [
|
||||||
|
{
|
||||||
|
user: {
|
||||||
|
login: 'notme',
|
||||||
|
type: 'User'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
async () => new Date().toDateString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
10
action.yml
10
action.yml
|
@ -113,7 +113,15 @@ inputs:
|
||||||
default: '30'
|
default: '30'
|
||||||
required: false
|
required: false
|
||||||
remove-stale-when-updated:
|
remove-stale-when-updated:
|
||||||
description: 'Remove stale labels from issues when they are updated or commented on.'
|
description: 'Remove stale labels from issues and pull requests when they are updated or commented on.'
|
||||||
|
default: 'true'
|
||||||
|
required: false
|
||||||
|
remove-issue-stale-when-updated:
|
||||||
|
description: 'Remove stale labels from issues when they are updated or commented on. Override "remove-stale-when-updated" option regarding only the issues.'
|
||||||
|
default: 'true'
|
||||||
|
required: false
|
||||||
|
remove-pr-stale-when-updated:
|
||||||
|
description: 'Remove stale labels from pull requests when they are updated or commented on. Override "remove-stale-when-updated" option regarding only the pull requests.'
|
||||||
default: 'true'
|
default: 'true'
|
||||||
required: false
|
required: false
|
||||||
debug-only:
|
debug-only:
|
||||||
|
|
|
@ -233,6 +233,7 @@ const option_1 = __nccwpck_require__(5931);
|
||||||
const get_humanized_date_1 = __nccwpck_require__(965);
|
const get_humanized_date_1 = __nccwpck_require__(965);
|
||||||
const is_date_more_recent_than_1 = __nccwpck_require__(1473);
|
const is_date_more_recent_than_1 = __nccwpck_require__(1473);
|
||||||
const is_valid_date_1 = __nccwpck_require__(891);
|
const is_valid_date_1 = __nccwpck_require__(891);
|
||||||
|
const is_boolean_1 = __nccwpck_require__(8236);
|
||||||
const is_labeled_1 = __nccwpck_require__(6792);
|
const is_labeled_1 = __nccwpck_require__(6792);
|
||||||
const should_mark_when_stale_1 = __nccwpck_require__(2461);
|
const should_mark_when_stale_1 = __nccwpck_require__(2461);
|
||||||
const words_to_list_1 = __nccwpck_require__(1883);
|
const words_to_list_1 = __nccwpck_require__(1883);
|
||||||
|
@ -519,18 +520,20 @@ class IssuesProcessor {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const issueLogger = new issue_logger_1.IssueLogger(issue);
|
const issueLogger = new issue_logger_1.IssueLogger(issue);
|
||||||
const markedStaleOn = (yield this.getLabelCreationDate(issue, staleLabel)) || issue.updated_at;
|
const markedStaleOn = (yield this.getLabelCreationDate(issue, staleLabel)) || issue.updated_at;
|
||||||
issueLogger.info(`$$type marked stale on: ${markedStaleOn}`);
|
issueLogger.info(`$$type marked stale on: ${chalk_1.default.cyan(markedStaleOn)}`);
|
||||||
const issueHasComments = yield this._hasCommentsSince(issue, markedStaleOn, actor);
|
const issueHasComments = yield this._hasCommentsSince(issue, markedStaleOn, actor);
|
||||||
issueLogger.info(`$$type has been commented on: ${issueHasComments}`);
|
issueLogger.info(`$$type has been commented on: ${chalk_1.default.cyan(issueHasComments)}`);
|
||||||
const daysBeforeClose = issue.isPullRequest
|
const daysBeforeClose = issue.isPullRequest
|
||||||
? this._getDaysBeforePrClose()
|
? this._getDaysBeforePrClose()
|
||||||
: this._getDaysBeforeIssueClose();
|
: this._getDaysBeforeIssueClose();
|
||||||
issueLogger.info(`Days before $$type close: ${daysBeforeClose}`);
|
issueLogger.info(`Days before $$type close: ${daysBeforeClose}`);
|
||||||
const issueHasUpdate = IssuesProcessor._updatedSince(issue.updated_at, daysBeforeClose);
|
const issueHasUpdate = IssuesProcessor._updatedSince(issue.updated_at, daysBeforeClose);
|
||||||
issueLogger.info(`$$type has been updated: ${issueHasUpdate}`);
|
issueLogger.info(`$$type has been updated: ${chalk_1.default.cyan(issueHasUpdate)}`);
|
||||||
// should we un-stale this issue?
|
// should we un-stale this issue?
|
||||||
if (this.options.removeStaleWhenUpdated && issueHasComments) {
|
if (this._shouldRemoveStaleWhenUpdated(issue) && issueHasComments) {
|
||||||
yield this._removeStaleLabel(issue, staleLabel);
|
yield this._removeStaleLabel(issue, staleLabel);
|
||||||
|
issueLogger.info(`Skipping the process since the $$type is now un-stale`);
|
||||||
|
return; // nothing to do because it is no longer stale
|
||||||
}
|
}
|
||||||
// now start closing logic
|
// now start closing logic
|
||||||
if (daysBeforeClose < 0) {
|
if (daysBeforeClose < 0) {
|
||||||
|
@ -592,7 +595,7 @@ class IssuesProcessor {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
issueLogger.error(`Error creating a comment: ${error.message}`);
|
issueLogger.error(`Error when creating a comment: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -607,7 +610,7 @@ class IssuesProcessor {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
issueLogger.error(`Error adding a label: ${error.message}`);
|
issueLogger.error(`Error when adding a label: ${error.message}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -633,7 +636,7 @@ class IssuesProcessor {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
issueLogger.error(`Error creating a comment: ${error.message}`);
|
issueLogger.error(`Error when creating a comment: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (closeLabel) {
|
if (closeLabel) {
|
||||||
|
@ -648,7 +651,7 @@ class IssuesProcessor {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
issueLogger.error(`Error adding a label: ${error.message}`);
|
issueLogger.error(`Error when adding a label: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -662,7 +665,7 @@ class IssuesProcessor {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
issueLogger.error(`Error updating this $$type: ${error.message}`);
|
issueLogger.error(`Error when updating this $$type: ${error.message}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -684,7 +687,7 @@ class IssuesProcessor {
|
||||||
return pullRequest.data;
|
return pullRequest.data;
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
issueLogger.error(`Error getting this $$type: ${error.message}`);
|
issueLogger.error(`Error when getting this $$type: ${error.message}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -703,7 +706,7 @@ class IssuesProcessor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const branch = pullRequest.head.ref;
|
const branch = pullRequest.head.ref;
|
||||||
issueLogger.info(`Deleting branch ${branch} from closed $$type`);
|
issueLogger.info(`Deleting the branch "${chalk_1.default.cyan(branch)}" from closed $$type`);
|
||||||
try {
|
try {
|
||||||
this._operations.consumeOperation();
|
this._operations.consumeOperation();
|
||||||
(_a = this._statistics) === null || _a === void 0 ? void 0 : _a.incrementDeletedBranchesCount();
|
(_a = this._statistics) === null || _a === void 0 ? void 0 : _a.incrementDeletedBranchesCount();
|
||||||
|
@ -714,7 +717,7 @@ class IssuesProcessor {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
issueLogger.error(`Error deleting branch ${branch} from $$type: ${error.message}`);
|
issueLogger.error(`Error when deleting the branch "${chalk_1.default.cyan(branch)}" from $$type: ${error.message}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -723,7 +726,7 @@ class IssuesProcessor {
|
||||||
var _a;
|
var _a;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const issueLogger = new issue_logger_1.IssueLogger(issue);
|
const issueLogger = new issue_logger_1.IssueLogger(issue);
|
||||||
issueLogger.info(`Removing label "${label}" from $$type`);
|
issueLogger.info(`Removing the label "${chalk_1.default.cyan(label)}" from the $$type...`);
|
||||||
this.removedLabelIssues.push(issue);
|
this.removedLabelIssues.push(issue);
|
||||||
if (this.options.debugOnly) {
|
if (this.options.debugOnly) {
|
||||||
return;
|
return;
|
||||||
|
@ -737,9 +740,10 @@ class IssuesProcessor {
|
||||||
issue_number: issue.number,
|
issue_number: issue.number,
|
||||||
name: label
|
name: label
|
||||||
});
|
});
|
||||||
|
issueLogger.info(`The label "${chalk_1.default.cyan(label)}" was removed`);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
issueLogger.error(`Error removing a label: ${error.message}`);
|
issueLogger.error(`Error when removing the label: "${chalk_1.default.cyan(error.message)}"`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -789,6 +793,18 @@ class IssuesProcessor {
|
||||||
}
|
}
|
||||||
return this.options.anyOfLabels;
|
return this.options.anyOfLabels;
|
||||||
}
|
}
|
||||||
|
_shouldRemoveStaleWhenUpdated(issue) {
|
||||||
|
if (issue.isPullRequest) {
|
||||||
|
if (is_boolean_1.isBoolean(this.options.removePrStaleWhenUpdated)) {
|
||||||
|
return this.options.removePrStaleWhenUpdated;
|
||||||
|
}
|
||||||
|
return this.options.removeStaleWhenUpdated;
|
||||||
|
}
|
||||||
|
if (is_boolean_1.isBoolean(this.options.removeIssueStaleWhenUpdated)) {
|
||||||
|
return this.options.removeIssueStaleWhenUpdated;
|
||||||
|
}
|
||||||
|
return this.options.removeStaleWhenUpdated;
|
||||||
|
}
|
||||||
_removeStaleLabel(issue, staleLabel) {
|
_removeStaleLabel(issue, staleLabel) {
|
||||||
var _a;
|
var _a;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
@ -808,7 +824,7 @@ class IssuesProcessor {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
if (is_labeled_1.isLabeled(issue, closeLabel)) {
|
if (is_labeled_1.isLabeled(issue, closeLabel)) {
|
||||||
issueLogger.info(`The $$type has a close label "${closeLabel}". Removing the close label...`);
|
issueLogger.info(`The $$type has a close label "${chalk_1.default.cyan(closeLabel)}". Removing the close label...`);
|
||||||
yield this._removeLabel(issue, closeLabel);
|
yield this._removeLabel(issue, closeLabel);
|
||||||
(_a = this._statistics) === null || _a === void 0 ? void 0 : _a.incrementDeletedCloseItemsLabelsCount(issue);
|
(_a = this._statistics) === null || _a === void 0 ? void 0 : _a.incrementDeletedCloseItemsLabelsCount(issue);
|
||||||
}
|
}
|
||||||
|
@ -1619,6 +1635,21 @@ function isValidDate(date) {
|
||||||
exports.isValidDate = isValidDate;
|
exports.isValidDate = isValidDate;
|
||||||
|
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ 8236:
|
||||||
|
/***/ ((__unused_webpack_module, exports) => {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
|
exports.isBoolean = void 0;
|
||||||
|
function isBoolean(value) {
|
||||||
|
return value === true || value === false;
|
||||||
|
}
|
||||||
|
exports.isBoolean = isBoolean;
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 6792:
|
/***/ 6792:
|
||||||
|
@ -1794,6 +1825,8 @@ function _getAndValidateArgs() {
|
||||||
anyOfPrLabels: core.getInput('any-of-pr-labels'),
|
anyOfPrLabels: core.getInput('any-of-pr-labels'),
|
||||||
operationsPerRun: parseInt(core.getInput('operations-per-run', { required: true })),
|
operationsPerRun: parseInt(core.getInput('operations-per-run', { required: true })),
|
||||||
removeStaleWhenUpdated: !(core.getInput('remove-stale-when-updated') === 'false'),
|
removeStaleWhenUpdated: !(core.getInput('remove-stale-when-updated') === 'false'),
|
||||||
|
removeIssueStaleWhenUpdated: _toOptionalBoolean(core.getInput('remove-issue-stale-when-updated')),
|
||||||
|
removePrStaleWhenUpdated: _toOptionalBoolean(core.getInput('remove-pr-stale-when-updated')),
|
||||||
debugOnly: core.getInput('debug-only') === 'true',
|
debugOnly: core.getInput('debug-only') === 'true',
|
||||||
ascending: core.getInput('ascending') === 'true',
|
ascending: core.getInput('ascending') === 'true',
|
||||||
skipStalePrMessage: core.getInput('skip-stale-pr-message') === 'true',
|
skipStalePrMessage: core.getInput('skip-stale-pr-message') === 'true',
|
||||||
|
|
|
@ -35,6 +35,8 @@ describe('Issue', (): void => {
|
||||||
anyOfPrLabels: '',
|
anyOfPrLabels: '',
|
||||||
operationsPerRun: 0,
|
operationsPerRun: 0,
|
||||||
removeStaleWhenUpdated: false,
|
removeStaleWhenUpdated: false,
|
||||||
|
removeIssueStaleWhenUpdated: undefined,
|
||||||
|
removePrStaleWhenUpdated: undefined,
|
||||||
repoToken: '',
|
repoToken: '',
|
||||||
skipStaleIssueMessage: false,
|
skipStaleIssueMessage: false,
|
||||||
skipStalePrMessage: false,
|
skipStalePrMessage: false,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {Option} from '../enums/option';
|
||||||
import {getHumanizedDate} from '../functions/dates/get-humanized-date';
|
import {getHumanizedDate} from '../functions/dates/get-humanized-date';
|
||||||
import {isDateMoreRecentThan} from '../functions/dates/is-date-more-recent-than';
|
import {isDateMoreRecentThan} from '../functions/dates/is-date-more-recent-than';
|
||||||
import {isValidDate} from '../functions/dates/is-valid-date';
|
import {isValidDate} from '../functions/dates/is-valid-date';
|
||||||
|
import {isBoolean} from '../functions/is-boolean';
|
||||||
import {isLabeled} from '../functions/is-labeled';
|
import {isLabeled} from '../functions/is-labeled';
|
||||||
import {shouldMarkWhenStale} from '../functions/should-mark-when-stale';
|
import {shouldMarkWhenStale} from '../functions/should-mark-when-stale';
|
||||||
import {wordsToList} from '../functions/words-to-list';
|
import {wordsToList} from '../functions/words-to-list';
|
||||||
|
@ -453,14 +454,16 @@ export class IssuesProcessor {
|
||||||
const issueLogger: IssueLogger = new IssueLogger(issue);
|
const issueLogger: IssueLogger = new IssueLogger(issue);
|
||||||
const markedStaleOn: string =
|
const markedStaleOn: string =
|
||||||
(await this.getLabelCreationDate(issue, staleLabel)) || issue.updated_at;
|
(await this.getLabelCreationDate(issue, staleLabel)) || issue.updated_at;
|
||||||
issueLogger.info(`$$type marked stale on: ${markedStaleOn}`);
|
issueLogger.info(`$$type marked stale on: ${chalk.cyan(markedStaleOn)}`);
|
||||||
|
|
||||||
const issueHasComments: boolean = await this._hasCommentsSince(
|
const issueHasComments: boolean = await this._hasCommentsSince(
|
||||||
issue,
|
issue,
|
||||||
markedStaleOn,
|
markedStaleOn,
|
||||||
actor
|
actor
|
||||||
);
|
);
|
||||||
issueLogger.info(`$$type has been commented on: ${issueHasComments}`);
|
issueLogger.info(
|
||||||
|
`$$type has been commented on: ${chalk.cyan(issueHasComments)}`
|
||||||
|
);
|
||||||
|
|
||||||
const daysBeforeClose: number = issue.isPullRequest
|
const daysBeforeClose: number = issue.isPullRequest
|
||||||
? this._getDaysBeforePrClose()
|
? this._getDaysBeforePrClose()
|
||||||
|
@ -472,11 +475,15 @@ export class IssuesProcessor {
|
||||||
issue.updated_at,
|
issue.updated_at,
|
||||||
daysBeforeClose
|
daysBeforeClose
|
||||||
);
|
);
|
||||||
issueLogger.info(`$$type has been updated: ${issueHasUpdate}`);
|
issueLogger.info(`$$type has been updated: ${chalk.cyan(issueHasUpdate)}`);
|
||||||
|
|
||||||
// should we un-stale this issue?
|
// should we un-stale this issue?
|
||||||
if (this.options.removeStaleWhenUpdated && issueHasComments) {
|
if (this._shouldRemoveStaleWhenUpdated(issue) && issueHasComments) {
|
||||||
await this._removeStaleLabel(issue, staleLabel);
|
await this._removeStaleLabel(issue, staleLabel);
|
||||||
|
|
||||||
|
issueLogger.info(`Skipping the process since the $$type is now un-stale`);
|
||||||
|
|
||||||
|
return; // nothing to do because it is no longer stale
|
||||||
}
|
}
|
||||||
|
|
||||||
// now start closing logic
|
// now start closing logic
|
||||||
|
@ -565,7 +572,7 @@ export class IssuesProcessor {
|
||||||
body: staleMessage
|
body: staleMessage
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
issueLogger.error(`Error creating a comment: ${error.message}`);
|
issueLogger.error(`Error when creating a comment: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -580,7 +587,7 @@ export class IssuesProcessor {
|
||||||
labels: [staleLabel]
|
labels: [staleLabel]
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
issueLogger.error(`Error adding a label: ${error.message}`);
|
issueLogger.error(`Error when adding a label: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,7 +617,7 @@ export class IssuesProcessor {
|
||||||
body: closeMessage
|
body: closeMessage
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
issueLogger.error(`Error creating a comment: ${error.message}`);
|
issueLogger.error(`Error when creating a comment: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,7 +632,7 @@ export class IssuesProcessor {
|
||||||
labels: [closeLabel]
|
labels: [closeLabel]
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
issueLogger.error(`Error adding a label: ${error.message}`);
|
issueLogger.error(`Error when adding a label: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,7 +646,7 @@ export class IssuesProcessor {
|
||||||
state: 'closed'
|
state: 'closed'
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
issueLogger.error(`Error updating this $$type: ${error.message}`);
|
issueLogger.error(`Error when updating this $$type: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -663,7 +670,7 @@ export class IssuesProcessor {
|
||||||
|
|
||||||
return pullRequest.data;
|
return pullRequest.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
issueLogger.error(`Error getting this $$type: ${error.message}`);
|
issueLogger.error(`Error when getting this $$type: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -687,7 +694,9 @@ export class IssuesProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
const branch = pullRequest.head.ref;
|
const branch = pullRequest.head.ref;
|
||||||
issueLogger.info(`Deleting branch ${branch} from closed $$type`);
|
issueLogger.info(
|
||||||
|
`Deleting the branch "${chalk.cyan(branch)}" from closed $$type`
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this._operations.consumeOperation();
|
this._operations.consumeOperation();
|
||||||
|
@ -699,7 +708,9 @@ export class IssuesProcessor {
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
issueLogger.error(
|
issueLogger.error(
|
||||||
`Error deleting branch ${branch} from $$type: ${error.message}`
|
`Error when deleting the branch "${chalk.cyan(branch)}" from $$type: ${
|
||||||
|
error.message
|
||||||
|
}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -708,7 +719,9 @@ export class IssuesProcessor {
|
||||||
private async _removeLabel(issue: Issue, label: string): Promise<void> {
|
private async _removeLabel(issue: Issue, label: string): Promise<void> {
|
||||||
const issueLogger: IssueLogger = new IssueLogger(issue);
|
const issueLogger: IssueLogger = new IssueLogger(issue);
|
||||||
|
|
||||||
issueLogger.info(`Removing label "${label}" from $$type`);
|
issueLogger.info(
|
||||||
|
`Removing the label "${chalk.cyan(label)}" from the $$type...`
|
||||||
|
);
|
||||||
this.removedLabelIssues.push(issue);
|
this.removedLabelIssues.push(issue);
|
||||||
|
|
||||||
if (this.options.debugOnly) {
|
if (this.options.debugOnly) {
|
||||||
|
@ -724,8 +737,11 @@ export class IssuesProcessor {
|
||||||
issue_number: issue.number,
|
issue_number: issue.number,
|
||||||
name: label
|
name: label
|
||||||
});
|
});
|
||||||
|
issueLogger.info(`The label "${chalk.cyan(label)}" was removed`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
issueLogger.error(`Error removing a label: ${error.message}`);
|
issueLogger.error(
|
||||||
|
`Error when removing the label: "${chalk.cyan(error.message)}"`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,6 +797,22 @@ export class IssuesProcessor {
|
||||||
return this.options.anyOfLabels;
|
return this.options.anyOfLabels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _shouldRemoveStaleWhenUpdated(issue: Issue): boolean {
|
||||||
|
if (issue.isPullRequest) {
|
||||||
|
if (isBoolean(this.options.removePrStaleWhenUpdated)) {
|
||||||
|
return this.options.removePrStaleWhenUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.options.removeStaleWhenUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBoolean(this.options.removeIssueStaleWhenUpdated)) {
|
||||||
|
return this.options.removeIssueStaleWhenUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.options.removeStaleWhenUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
private async _removeStaleLabel(
|
private async _removeStaleLabel(
|
||||||
issue: Issue,
|
issue: Issue,
|
||||||
staleLabel: Readonly<string>
|
staleLabel: Readonly<string>
|
||||||
|
@ -813,7 +845,9 @@ export class IssuesProcessor {
|
||||||
|
|
||||||
if (isLabeled(issue, closeLabel)) {
|
if (isLabeled(issue, closeLabel)) {
|
||||||
issueLogger.info(
|
issueLogger.info(
|
||||||
`The $$type has a close label "${closeLabel}". Removing the close label...`
|
`The $$type has a close label "${chalk.cyan(
|
||||||
|
closeLabel
|
||||||
|
)}". Removing the close label...`
|
||||||
);
|
);
|
||||||
|
|
||||||
await this._removeLabel(issue, closeLabel);
|
await this._removeLabel(issue, closeLabel);
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import {isBoolean} from './is-boolean';
|
||||||
|
|
||||||
|
describe('isBoolean()', (): void => {
|
||||||
|
describe.each([0, 1, undefined, null, ''])(
|
||||||
|
'when the given value is not a boolean',
|
||||||
|
(value): void => {
|
||||||
|
it('should return false', (): void => {
|
||||||
|
expect.assertions(1);
|
||||||
|
|
||||||
|
const result = isBoolean(value);
|
||||||
|
|
||||||
|
expect(result).toStrictEqual(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
describe.each([false, true])(
|
||||||
|
'when the given value is a boolean',
|
||||||
|
(value): void => {
|
||||||
|
it('should return true', (): void => {
|
||||||
|
expect.assertions(1);
|
||||||
|
|
||||||
|
const result = isBoolean(value);
|
||||||
|
|
||||||
|
expect(result).toStrictEqual(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
|
@ -0,0 +1,3 @@
|
||||||
|
export function isBoolean(value: unknown): value is boolean {
|
||||||
|
return value === true || value === false;
|
||||||
|
}
|
|
@ -26,6 +26,8 @@ export interface IIssuesProcessorOptions {
|
||||||
anyOfPrLabels: string;
|
anyOfPrLabels: string;
|
||||||
operationsPerRun: number;
|
operationsPerRun: number;
|
||||||
removeStaleWhenUpdated: boolean;
|
removeStaleWhenUpdated: boolean;
|
||||||
|
removeIssueStaleWhenUpdated: boolean | undefined;
|
||||||
|
removePrStaleWhenUpdated: boolean | undefined;
|
||||||
debugOnly: boolean;
|
debugOnly: boolean;
|
||||||
ascending: boolean;
|
ascending: boolean;
|
||||||
skipStaleIssueMessage: boolean;
|
skipStaleIssueMessage: boolean;
|
||||||
|
|
|
@ -49,6 +49,12 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
|
||||||
removeStaleWhenUpdated: !(
|
removeStaleWhenUpdated: !(
|
||||||
core.getInput('remove-stale-when-updated') === 'false'
|
core.getInput('remove-stale-when-updated') === 'false'
|
||||||
),
|
),
|
||||||
|
removeIssueStaleWhenUpdated: _toOptionalBoolean(
|
||||||
|
core.getInput('remove-issue-stale-when-updated')
|
||||||
|
),
|
||||||
|
removePrStaleWhenUpdated: _toOptionalBoolean(
|
||||||
|
core.getInput('remove-pr-stale-when-updated')
|
||||||
|
),
|
||||||
debugOnly: core.getInput('debug-only') === 'true',
|
debugOnly: core.getInput('debug-only') === 'true',
|
||||||
ascending: core.getInput('ascending') === 'true',
|
ascending: core.getInput('ascending') === 'true',
|
||||||
skipStalePrMessage: core.getInput('skip-stale-pr-message') === 'true',
|
skipStalePrMessage: core.getInput('skip-stale-pr-message') === 'true',
|
||||||
|
|
Loading…
Reference in New Issue