mirror of
https://github.com/dessant/lock-threads.git
synced 2026-03-13 01:27:03 -04:00
feat: add new filtering and labeling options, update input parameter names
BREAKING CHANGE: input parameter names have changed
This commit is contained in:
231
README.md
231
README.md
@@ -16,7 +16,7 @@ please consider contributing with
|
||||
|
||||
## Usage
|
||||
|
||||
Create a `lock.yml` workflow file in the `.github/workflows` directory,
|
||||
Create the `lock.yml` workflow file in the `.github/workflows` directory,
|
||||
use one of the [example workflows](#examples) to get started.
|
||||
|
||||
### Inputs
|
||||
@@ -28,44 +28,118 @@ The action can be configured using [input parameters](https://docs.github.com/en
|
||||
- GitHub access token, value must be `${{ github.token }}` or an encrypted
|
||||
secret that contains a [personal access token](#using-a-personal-access-token)
|
||||
- Optional, defaults to `${{ github.token }}`
|
||||
- **`issue-lock-inactive-days`**
|
||||
- **`issue-inactive-days`**
|
||||
- Number of days of inactivity before a closed issue is locked
|
||||
- Optional, defaults to `365`
|
||||
- **`issue-exclude-created-before`**
|
||||
- Do not lock issues created before a given timestamp,
|
||||
- **`exclude-issue-created-before`**
|
||||
- Do not lock issues created before a given date,
|
||||
value must follow ISO 8601, ignored
|
||||
when `exclude-issue-created-between` is set
|
||||
- Optional, defaults to `''`
|
||||
- **`exclude-issue-created-after`**
|
||||
- Do not lock issues created after a given date,
|
||||
value must follow ISO 8601, ignored
|
||||
when `exclude-issue-created-between` is set
|
||||
- Optional, defaults to `''`
|
||||
- **`exclude-issue-created-between`**
|
||||
- Do not lock issues created in a given time interval,
|
||||
value must follow ISO 8601
|
||||
- Optional, defaults to `''`
|
||||
- **`issue-exclude-labels`**
|
||||
- Do not lock issues with these labels, value must be
|
||||
- **`exclude-issue-closed-before`**
|
||||
- Do not lock issues closed before a given date,
|
||||
value must follow ISO 8601, ignored
|
||||
when `exclude-issue-closed-between` is set
|
||||
- Optional, defaults to `''`
|
||||
- **`exclude-issue-closed-after`**
|
||||
- Do not lock issues closed after a given date,
|
||||
value must follow ISO 8601, ignored
|
||||
when `exclude-issue-closed-between` is set
|
||||
- Optional, defaults to `''`
|
||||
- **`exclude-issue-closed-between`**
|
||||
- Do not lock issues closed in a given time interval,
|
||||
value must follow ISO 8601
|
||||
- Optional, defaults to `''`
|
||||
- **`include-any-issue-labels`**
|
||||
- Only lock issues with any of these labels, value must be
|
||||
a comma separated list of labels or `''`, ignored
|
||||
when `include-all-issue-labels` is set
|
||||
- Optional, defaults to `''`
|
||||
- **`include-all-issue-labels`**
|
||||
- Only lock issues with all these labels, value must be
|
||||
a comma separated list of labels or `''`
|
||||
- Optional, defaults to `''`
|
||||
- **`issue-lock-labels`**
|
||||
- **`exclude-any-issue-labels`**
|
||||
- Do not lock issues with any of these labels, value must be
|
||||
a comma separated list of labels or `''`
|
||||
- Optional, defaults to `''`
|
||||
- **`add-issue-labels`**
|
||||
- Labels to add before locking an issue, value must be
|
||||
a comma separated list of labels or `''`
|
||||
- Optional, defaults to `''`
|
||||
- **`issue-lock-comment`**
|
||||
- **`remove-issue-labels`**
|
||||
- Labels to remove before locking an issue, value must be
|
||||
a comma separated list of labels or `''`
|
||||
- Optional, defaults to `''`
|
||||
- **`issue-comment`**
|
||||
- Comment to post before locking an issue
|
||||
- Optional, defaults to `''`
|
||||
- **`issue-lock-reason`**
|
||||
- Reason for locking an issue, value must be one
|
||||
of `resolved`, `off-topic`, `too heated`, `spam` or `''`
|
||||
- Optional, defaults to `resolved`
|
||||
- **`pr-lock-inactive-days`**
|
||||
- **`pr-inactive-days`**
|
||||
- Number of days of inactivity before a closed pull request is locked
|
||||
- Optional, defaults to `365`
|
||||
- **`pr-exclude-created-before`**
|
||||
- Do not lock pull requests created before a given timestamp,
|
||||
- **`exclude-pr-created-before`**
|
||||
- Do not lock pull requests created before a given date,
|
||||
value must follow ISO 8601, ignored
|
||||
when `exclude-pr-created-between` is set
|
||||
- Optional, defaults to `''`
|
||||
- **`exclude-pr-created-after`**
|
||||
- Do not lock pull requests created after a given date,
|
||||
value must follow ISO 8601, ignored
|
||||
when `exclude-pr-created-between` is set
|
||||
- Optional, defaults to `''`
|
||||
- **`exclude-pr-created-between`**
|
||||
- Do not lock pull requests created in a given time interval,
|
||||
value must follow ISO 8601
|
||||
- Optional, defaults to `''`
|
||||
- **`pr-exclude-labels`**
|
||||
- Do not lock pull requests with these labels, value must
|
||||
be a comma separated list of labels or `''`
|
||||
- **`exclude-pr-closed-before`**
|
||||
- Do not lock pull requests closed before a given date,
|
||||
value must follow ISO 8601, ignored
|
||||
when `exclude-pr-closed-between` is set
|
||||
- Optional, defaults to `''`
|
||||
- **`pr-lock-labels`**
|
||||
- **`exclude-pr-closed-after`**
|
||||
- Do not lock pull requests closed after a given date,
|
||||
value must follow ISO 8601, ignored
|
||||
when `exclude-pr-closed-between` is set
|
||||
- Optional, defaults to `''`
|
||||
- **`exclude-pr-closed-between`**
|
||||
- Do not lock pull requests closed in a given time interval,
|
||||
value must follow ISO 8601
|
||||
- Optional, defaults to `''`
|
||||
- **`include-any-pr-labels`**
|
||||
- Only lock pull requests with any of these labels, value must be
|
||||
a comma separated list of labels or `''`, ignored
|
||||
when `include-all-pr-labels` is set
|
||||
- Optional, defaults to `''`
|
||||
- **`include-all-pr-labels`**
|
||||
- Only lock pull requests with all these labels, value must be
|
||||
a comma separated list of labels or `''`
|
||||
- Optional, defaults to `''`
|
||||
- **`exclude-any-pr-labels`**
|
||||
- Do not lock pull requests with any of these labels, value must be
|
||||
a comma separated list of labels or `''`
|
||||
- Optional, defaults to `''`
|
||||
- **`add-pr-labels`**
|
||||
- Labels to add before locking a pull request, value must be
|
||||
a comma separated list of labels or `''`
|
||||
- Optional, defaults to `''`
|
||||
- **`pr-lock-comment`**
|
||||
- **`remove-pr-labels`**
|
||||
- Labels to remove before locking a pull request, value must be
|
||||
a comma separated list of labels or `''`
|
||||
- Optional, defaults to `''`
|
||||
- **`pr-comment`**
|
||||
- Comment to post before locking a pull request
|
||||
- Optional, defaults to `''`
|
||||
- **`pr-lock-reason`**
|
||||
@@ -76,6 +150,9 @@ The action can be configured using [input parameters](https://docs.github.com/en
|
||||
- Limit locking to only issues or pull requests, value must be
|
||||
one of `issues`, `prs` or `''`
|
||||
- Optional, defaults to `''`
|
||||
- **`log-output`**
|
||||
- Log output parameters, value must be either `true` or `false`
|
||||
- Optional, defaults to `false`
|
||||
|
||||
### Outputs
|
||||
|
||||
@@ -92,7 +169,8 @@ The action can be configured using [input parameters](https://docs.github.com/en
|
||||
## Examples
|
||||
|
||||
The following workflow will search once an hour for closed issues
|
||||
and pull requests that can be locked.
|
||||
and pull requests that have not had any activity
|
||||
in the past year and can be locked.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```yaml
|
||||
@@ -114,7 +192,7 @@ jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v2
|
||||
- uses: dessant/lock-threads@v3
|
||||
```
|
||||
|
||||
Edit the workflow after the initial backlog of issues and pull requests
|
||||
@@ -153,25 +231,42 @@ jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v2
|
||||
- uses: dessant/lock-threads@v3
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
issue-lock-inactive-days: '365'
|
||||
issue-exclude-created-before: ''
|
||||
issue-exclude-labels: ''
|
||||
issue-lock-labels: ''
|
||||
issue-lock-comment: ''
|
||||
issue-inactive-days: '365'
|
||||
exclude-issue-created-before: ''
|
||||
exclude-issue-created-after: ''
|
||||
exclude-issue-created-between: ''
|
||||
exclude-issue-closed-before: ''
|
||||
exclude-issue-closed-after: ''
|
||||
exclude-issue-closed-between: ''
|
||||
include-any-issue-labels: ''
|
||||
include-all-issue-labels: ''
|
||||
exclude-any-issue-labels: ''
|
||||
add-issue-labels: ''
|
||||
remove-issue-labels: ''
|
||||
issue-comment: ''
|
||||
issue-lock-reason: 'resolved'
|
||||
pr-lock-inactive-days: '365'
|
||||
pr-exclude-created-before: ''
|
||||
pr-exclude-labels: ''
|
||||
pr-lock-labels: ''
|
||||
pr-lock-comment: ''
|
||||
pr-inactive-days: '365'
|
||||
exclude-pr-created-before: ''
|
||||
exclude-pr-created-after: ''
|
||||
exclude-pr-created-between: ''
|
||||
exclude-pr-closed-before: ''
|
||||
exclude-pr-closed-after: ''
|
||||
exclude-pr-closed-between: ''
|
||||
include-any-pr-labels: ''
|
||||
include-all-pr-labels: ''
|
||||
exclude-any-pr-labels: ''
|
||||
add-pr-labels: ''
|
||||
remove-pr-labels: ''
|
||||
pr-comment: ''
|
||||
pr-lock-reason: 'resolved'
|
||||
process-only: ''
|
||||
log-output: false
|
||||
```
|
||||
|
||||
### Excluding issues and pull requests
|
||||
### Filtering issues and pull requests
|
||||
|
||||
This step will lock only issues, and exclude issues created before 2018,
|
||||
or those with the `upstream` or `help-wanted` labels applied.
|
||||
@@ -179,10 +274,10 @@ or those with the `upstream` or `help-wanted` labels applied.
|
||||
<!-- prettier-ignore -->
|
||||
```yaml
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v2
|
||||
- uses: dessant/lock-threads@v3
|
||||
with:
|
||||
issue-exclude-created-before: '2018-01-01T00:00:00Z'
|
||||
issue-exclude-labels: 'upstream, help-wanted'
|
||||
exclude-issue-created-before: '2018-01-01T00:00:00Z'
|
||||
exclude-any-issue-labels: 'upstream, help-wanted'
|
||||
process-only: 'issues'
|
||||
```
|
||||
|
||||
@@ -192,12 +287,51 @@ with the `wip` label applied.
|
||||
<!-- prettier-ignore -->
|
||||
```yaml
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v2
|
||||
- uses: dessant/lock-threads@v3
|
||||
with:
|
||||
pr-exclude-labels: 'wip'
|
||||
exclude-any-pr-labels: 'wip'
|
||||
process-only: 'prs'
|
||||
```
|
||||
|
||||
This step will lock only issues, and exclude issues closed before 2018,
|
||||
or those created in 2018 and 2019.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```yaml
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v3
|
||||
with:
|
||||
exclude-issue-created-between: '2018-01-01T00:00:00Z/2019-12-31T23:59:59.999Z'
|
||||
exclude-issue-closed-before: '2018-01-01T00:00:00Z'
|
||||
process-only: 'issues'
|
||||
```
|
||||
|
||||
This step will lock issues that have the `incomplete` _or_ `invalid`
|
||||
labels applied, and pull requests that have the `qa: done` _and_ `published`
|
||||
labels applied.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```yaml
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v3
|
||||
with:
|
||||
include-any-issue-labels: 'incomplete, invalid'
|
||||
include-all-pr-labels: 'qa: done, published'
|
||||
|
||||
```
|
||||
|
||||
This step will lock issues that have not had any activity in the past 180 days.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```yaml
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v3
|
||||
with:
|
||||
issue-inactive-days: '180'
|
||||
process-only: 'issues'
|
||||
|
||||
```
|
||||
|
||||
### Commenting and labeling
|
||||
|
||||
This step will post a comment on issues and pull requests before locking them,
|
||||
@@ -206,19 +340,32 @@ and apply the `outdated` label to issues.
|
||||
<!-- prettier-ignore -->
|
||||
```yaml
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v2
|
||||
- uses: dessant/lock-threads@v3
|
||||
with:
|
||||
issue-lock-labels: 'outdated'
|
||||
issue-lock-comment: >
|
||||
add-issue-labels: 'outdated'
|
||||
issue-comment: >
|
||||
This issue has been automatically locked since there
|
||||
has not been any recent activity after it was closed.
|
||||
Please open a new issue for related bugs.
|
||||
pr-lock-comment: >
|
||||
pr-comment: >
|
||||
This pull request has been automatically locked since there
|
||||
has not been any recent activity after it was closed.
|
||||
Please open a new issue for related bugs.
|
||||
```
|
||||
|
||||
This step will apply the `qa: done` and `archived` labels,
|
||||
and remove the `qa: primary` and `needs: user feedback` labels
|
||||
before locking issues.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```yaml
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v3
|
||||
with:
|
||||
add-issue-labels: 'qa: done, archived'
|
||||
remove-issue-labels: 'qa: primary, needs: user feedback'
|
||||
```
|
||||
|
||||
### Using a personal access token
|
||||
|
||||
The action uses an installation access token by default to interact with GitHub.
|
||||
@@ -234,7 +381,7 @@ using the `github-token` input parameter.
|
||||
<!-- prettier-ignore -->
|
||||
```yaml
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v2
|
||||
- uses: dessant/lock-threads@v3
|
||||
with:
|
||||
github-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
```
|
||||
@@ -248,9 +395,9 @@ applying or removing milestones, or pushing commits.
|
||||
|
||||
An easy way to check and see which issues or pull requests will initially
|
||||
be locked is to add the `updated` search qualifier to either the issue
|
||||
or pull request page filter for your repository:
|
||||
or pull request search field for your repository:
|
||||
`is:closed is:unlocked updated:<2018-12-20`.
|
||||
Adjust the date to be 365 days ago (or whatever you set for `*-lock-inactive-days`)
|
||||
Adjust the date to be 365 days ago (or whatever you set for `*-inactive-days`)
|
||||
to see which issues or pull requests will be locked.
|
||||
|
||||
## Why are only some issues and pull requests processed?
|
||||
|
||||
79
action.yml
79
action.yml
@@ -5,37 +5,85 @@ inputs:
|
||||
github-token:
|
||||
description: 'GitHub access token'
|
||||
default: '${{ github.token }}'
|
||||
issue-lock-inactive-days:
|
||||
issue-inactive-days:
|
||||
description: 'Number of days of inactivity before a closed issue is locked'
|
||||
default: '365'
|
||||
issue-exclude-created-before:
|
||||
description: 'Do not lock issues created before a given timestamp, value must follow ISO 8601'
|
||||
exclude-issue-created-before:
|
||||
description: 'Do not lock issues created before a given date, value must follow ISO 8601'
|
||||
default: ''
|
||||
issue-exclude-labels:
|
||||
description: 'Do not lock issues with these labels, value must be a comma separated list of labels'
|
||||
exclude-issue-created-after:
|
||||
description: 'Do not lock issues created after a given date, value must follow ISO 8601'
|
||||
default: ''
|
||||
issue-lock-labels:
|
||||
exclude-issue-created-between:
|
||||
description: 'Do not lock issues created in a given time interval, value must follow ISO 8601'
|
||||
default: ''
|
||||
exclude-issue-closed-before:
|
||||
description: 'Do not lock issues closed before a given date, value must follow ISO 8601'
|
||||
default: ''
|
||||
exclude-issue-closed-after:
|
||||
description: 'Do not lock issues closed after a given date, value must follow ISO 8601'
|
||||
default: ''
|
||||
exclude-issue-closed-between:
|
||||
description: 'Do not lock issues closed in a given time interval, value must follow ISO 8601'
|
||||
default: ''
|
||||
include-any-issue-labels:
|
||||
description: 'Only lock issues with any of these labels, value must be a comma separated list of labels'
|
||||
default: ''
|
||||
include-all-issue-labels:
|
||||
description: 'Only lock issues with all these labels, value must be a comma separated list of labels'
|
||||
default: ''
|
||||
exclude-any-issue-labels:
|
||||
description: 'Do not lock issues with any of these labels, value must be a comma separated list of labels'
|
||||
default: ''
|
||||
add-issue-labels:
|
||||
description: 'Labels to add before locking an issue, value must be a comma separated list of labels'
|
||||
default: ''
|
||||
issue-lock-comment:
|
||||
remove-issue-labels:
|
||||
description: 'Labels to remove before locking an issue, value must be a comma separated list of labels'
|
||||
default: ''
|
||||
issue-comment:
|
||||
description: 'Comment to post before locking an issue'
|
||||
default: ''
|
||||
issue-lock-reason:
|
||||
description: 'Reason for locking an issue, value must be one of `resolved`, `off-topic`, `too heated` or `spam`'
|
||||
default: 'resolved'
|
||||
pr-lock-inactive-days:
|
||||
pr-inactive-days:
|
||||
description: 'Number of days of inactivity before a closed pull request is locked'
|
||||
default: '365'
|
||||
pr-exclude-created-before:
|
||||
description: 'Do not lock pull requests created before a given timestamp, value must follow ISO 8601'
|
||||
exclude-pr-created-before:
|
||||
description: 'Do not lock pull requests created before a given date, value must follow ISO 8601'
|
||||
default: ''
|
||||
pr-exclude-labels:
|
||||
description: 'Do not lock pull requests with these labels, value must be a comma separated list of labels'
|
||||
exclude-pr-created-after:
|
||||
description: 'Do not lock pull requests created after a given date, value must follow ISO 8601'
|
||||
default: ''
|
||||
pr-lock-labels:
|
||||
exclude-pr-created-between:
|
||||
description: 'Do not lock pull requests created in a given time interval, value must follow ISO 8601'
|
||||
default: ''
|
||||
exclude-pr-closed-before:
|
||||
description: 'Do not lock pull requests closed before a given date, value must follow ISO 8601'
|
||||
default: ''
|
||||
exclude-pr-closed-after:
|
||||
description: 'Do not lock pull requests closed after a given date, value must follow ISO 8601'
|
||||
default: ''
|
||||
exclude-pr-closed-between:
|
||||
description: 'Do not lock pull requests closed in a given time interval, value must follow ISO 8601'
|
||||
default: ''
|
||||
include-any-pr-labels:
|
||||
description: 'Only lock pull requests with any of these labels, value must be a comma separated list of labels'
|
||||
default: ''
|
||||
include-all-pr-labels:
|
||||
description: 'Only lock pull requests with all these labels, value must be a comma separated list of labels'
|
||||
default: ''
|
||||
exclude-any-pr-labels:
|
||||
description: 'Do not lock pull requests with any of these labels, value must be a comma separated list of labels'
|
||||
default: ''
|
||||
add-pr-labels:
|
||||
description: 'Labels to add before locking a pull request, value must be a comma separated list of labels'
|
||||
default: ''
|
||||
pr-lock-comment:
|
||||
remove-pr-labels:
|
||||
description: 'Labels to remove before locking a pull request, value must be a comma separated list of labels'
|
||||
default: ''
|
||||
pr-comment:
|
||||
description: 'Comment to post before locking a pull request'
|
||||
default: ''
|
||||
pr-lock-reason:
|
||||
@@ -44,6 +92,9 @@ inputs:
|
||||
process-only:
|
||||
description: 'Limit locking to only issues or pull requests, value must be one of `issues` or `prs`'
|
||||
default: ''
|
||||
log-output:
|
||||
description: 'Log output parameters, value must be either `true` or `false`'
|
||||
default: false
|
||||
outputs:
|
||||
issues:
|
||||
description: 'Issues that have been locked, value is a JSON string'
|
||||
|
||||
126
src/index.js
126
src/index.js
@@ -23,19 +23,31 @@ class App {
|
||||
|
||||
async lockThreads() {
|
||||
const type = this.config['process-only'];
|
||||
const threadTypes = type ? [type] : ['issue', 'pr'];
|
||||
const logOutput = this.config['log-output'];
|
||||
|
||||
const threadTypes = type ? [type] : ['issue', 'pr'];
|
||||
for (const item of threadTypes) {
|
||||
const threads = await this.lock(item);
|
||||
|
||||
core.debug(`Setting output (${item}s)`);
|
||||
core.setOutput(`${item}s`, threads.length ? JSON.stringify(threads) : '');
|
||||
if (threads.length) {
|
||||
core.setOutput(`${item}s`, JSON.stringify(threads));
|
||||
|
||||
if (logOutput) {
|
||||
core.info(`Output (${item}s):`);
|
||||
core.info(JSON.stringify(threads, null, 2));
|
||||
}
|
||||
} else {
|
||||
core.setOutput(`${item}s`, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async lock(type) {
|
||||
const repo = github.context.repo;
|
||||
const lockLabels = this.config[`${type}-lock-labels`];
|
||||
const lockComment = this.config[`${type}-lock-comment`];
|
||||
const addLabels = this.config[`add-${type}-labels`];
|
||||
const removeLabels = this.config[`remove-${type}-labels`];
|
||||
const comment = this.config[`${type}-comment`];
|
||||
const lockReason = this.config[`${type}-lock-reason`];
|
||||
|
||||
const threads = [];
|
||||
@@ -44,12 +56,12 @@ class App {
|
||||
for (const result of results) {
|
||||
const issue = {...repo, issue_number: result.number};
|
||||
|
||||
if (lockComment) {
|
||||
if (comment) {
|
||||
core.debug(`Commenting (${type}: ${issue.issue_number})`);
|
||||
try {
|
||||
await this.client.rest.issues.createComment({
|
||||
...issue,
|
||||
body: lockComment
|
||||
body: comment
|
||||
});
|
||||
} catch (err) {
|
||||
if (!/cannot be modified.*discussion/i.test(err.message)) {
|
||||
@@ -58,12 +70,39 @@ class App {
|
||||
}
|
||||
}
|
||||
|
||||
if (lockLabels) {
|
||||
core.debug(`Labeling (${type}: ${issue.issue_number})`);
|
||||
await this.client.rest.issues.addLabels({
|
||||
...issue,
|
||||
labels: lockLabels
|
||||
});
|
||||
if (addLabels || removeLabels) {
|
||||
const {data: issueData} = await this.client.rest.issues.get({...issue});
|
||||
|
||||
if (addLabels) {
|
||||
const currentLabels = issueData.labels.map(label => label.name);
|
||||
const newLabels = addLabels.filter(
|
||||
label => !currentLabels.includes(label)
|
||||
);
|
||||
|
||||
if (newLabels.length) {
|
||||
core.debug(`Labeling (${type}: ${issue.issue_number})`);
|
||||
await this.client.rest.issues.addLabels({
|
||||
...issue,
|
||||
labels: newLabels
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (removeLabels) {
|
||||
const currentLabels = issueData.labels.map(label => label.name);
|
||||
const matchingLabels = currentLabels.filter(label =>
|
||||
removeLabels.includes(label)
|
||||
);
|
||||
if (matchingLabels.length) {
|
||||
core.debug(`Unlabeling (${type}: ${issue.issue_number})`);
|
||||
for (const label of matchingLabels) {
|
||||
await this.client.rest.issues.removeLabel({
|
||||
...issue,
|
||||
name: label
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
core.debug(`Locking (${type}: ${issue.issue_number})`);
|
||||
@@ -89,22 +128,41 @@ class App {
|
||||
|
||||
async search(type) {
|
||||
const {owner, repo} = github.context.repo;
|
||||
const timestamp = this.getUpdatedTimestamp(
|
||||
this.config[`${type}-lock-inactive-days`]
|
||||
const updatedTime = this.getUpdatedTimestamp(
|
||||
this.config[`${type}-inactive-days`]
|
||||
);
|
||||
let query = `repo:${owner}/${repo} updated:<${timestamp} is:closed is:unlocked`;
|
||||
let query = `repo:${owner}/${repo} updated:<${updatedTime} is:closed is:unlocked`;
|
||||
|
||||
const excludeLabels = this.config[`${type}-exclude-labels`];
|
||||
if (excludeLabels) {
|
||||
const queryPart = excludeLabels
|
||||
.map(label => `-label:"${label}"`)
|
||||
.join(' ');
|
||||
query += ` ${queryPart}`;
|
||||
const includeAnyLabels = this.config[`include-any-${type}-labels`];
|
||||
const includeAllLabels = this.config[`include-all-${type}-labels`];
|
||||
|
||||
if (includeAllLabels) {
|
||||
query += ` ${includeAllLabels
|
||||
.map(label => `label:"${label}"`)
|
||||
.join(' ')}`;
|
||||
} else if (includeAnyLabels) {
|
||||
query += ` label:${includeAnyLabels.join(',')}`;
|
||||
}
|
||||
|
||||
const excludeCreatedBefore = this.config[`${type}-exclude-created-before`];
|
||||
if (excludeCreatedBefore) {
|
||||
query += ` created:>${this.getISOTimestamp(excludeCreatedBefore)}`;
|
||||
const excludeAnyLabels = this.config[`exclude-any-${type}-labels`];
|
||||
if (excludeAnyLabels) {
|
||||
query += ` -label:${excludeAnyLabels.join(',')}`;
|
||||
}
|
||||
|
||||
const excludeCreatedQuery = this.getFilterByDateQuery({
|
||||
type,
|
||||
qualifier: 'created'
|
||||
});
|
||||
if (excludeCreatedQuery) {
|
||||
query += ` ${excludeCreatedQuery}`;
|
||||
}
|
||||
|
||||
const excludeClosedQuery = this.getFilterByDateQuery({
|
||||
type,
|
||||
qualifier: 'closed'
|
||||
});
|
||||
if (excludeClosedQuery) {
|
||||
query += ` ${excludeClosedQuery}`;
|
||||
}
|
||||
|
||||
if (type === 'issue') {
|
||||
@@ -127,6 +185,26 @@ class App {
|
||||
return results.filter(issue => !issue.locked);
|
||||
}
|
||||
|
||||
getFilterByDateQuery({type, qualifier = 'created'} = {}) {
|
||||
const beforeDate = this.config[`exclude-${type}-${qualifier}-before`];
|
||||
const afterDate = this.config[`exclude-${type}-${qualifier}-after`];
|
||||
const betweenDates = this.config[`exclude-${type}-${qualifier}-between`];
|
||||
|
||||
if (betweenDates) {
|
||||
return `-${qualifier}:${betweenDates
|
||||
.map(date => this.getISOTimestamp(date))
|
||||
.join('..')}`;
|
||||
} else if (beforeDate && afterDate) {
|
||||
return `${qualifier}:${this.getISOTimestamp(
|
||||
beforeDate
|
||||
)}..${this.getISOTimestamp(afterDate)}`;
|
||||
} else if (beforeDate) {
|
||||
return `${qualifier}:>${this.getISOTimestamp(beforeDate)}`;
|
||||
} else if (afterDate) {
|
||||
return `${qualifier}:<${this.getISOTimestamp(afterDate)}`;
|
||||
}
|
||||
}
|
||||
|
||||
getUpdatedTimestamp(days) {
|
||||
const ttl = days * 24 * 60 * 60 * 1000;
|
||||
const date = new Date(new Date() - ttl);
|
||||
|
||||
246
src/schema.js
246
src/schema.js
@@ -1,134 +1,180 @@
|
||||
const Joi = require('joi');
|
||||
|
||||
const extendedJoi = Joi.extend({
|
||||
type: 'stringList',
|
||||
base: Joi.array(),
|
||||
coerce: {
|
||||
from: 'string',
|
||||
method(value) {
|
||||
value = value.trim();
|
||||
if (value) {
|
||||
value = value
|
||||
.split(',')
|
||||
.map(item => item.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
const extendedJoi = Joi.extend(joi => {
|
||||
return {
|
||||
type: 'stringList',
|
||||
base: joi.array(),
|
||||
coerce: {
|
||||
from: 'string',
|
||||
method(value, helpers) {
|
||||
value = value.trim();
|
||||
if (value) {
|
||||
value = value
|
||||
.split(',')
|
||||
.map(item => item.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
return {value};
|
||||
}
|
||||
}
|
||||
}).extend({
|
||||
type: 'processOnly',
|
||||
base: Joi.string(),
|
||||
coerce: {
|
||||
from: 'string',
|
||||
method(value) {
|
||||
value = value.trim();
|
||||
if (['issues', 'prs'].includes(value)) {
|
||||
value = value.slice(0, -1);
|
||||
return {value};
|
||||
}
|
||||
|
||||
return {value};
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
})
|
||||
.extend(joi => {
|
||||
return {
|
||||
type: 'timeInterval',
|
||||
base: joi.array(),
|
||||
messages: {
|
||||
'timeInterval.asc':
|
||||
'{{#label}} the start date must be earlier than the end date'
|
||||
},
|
||||
coerce: {
|
||||
from: 'string',
|
||||
method(value, helpers) {
|
||||
value = value.trim();
|
||||
if (value) {
|
||||
value = value
|
||||
.split('/')
|
||||
.map(item => item.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
return {value};
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
asc: {
|
||||
validate(value, helpers, args, options) {
|
||||
if (value[0] < value[1]) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return helpers.error('timeInterval.asc');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
})
|
||||
.extend(joi => {
|
||||
return {
|
||||
type: 'processOnly',
|
||||
base: joi.string(),
|
||||
coerce: {
|
||||
from: 'string',
|
||||
method(value, helpers) {
|
||||
value = value.trim();
|
||||
if (['issues', 'prs'].includes(value)) {
|
||||
value = value.slice(0, -1);
|
||||
}
|
||||
|
||||
return {value};
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const joiDate = Joi.alternatives().try(
|
||||
Joi.date()
|
||||
// .iso()
|
||||
.min('1970-01-01T00:00:00Z')
|
||||
.max('2970-12-31T23:59:59Z'),
|
||||
Joi.string().trim().valid('')
|
||||
);
|
||||
|
||||
const joiTimeInterval = Joi.alternatives().try(
|
||||
extendedJoi
|
||||
.timeInterval()
|
||||
.items(
|
||||
Joi.date().iso().min('1970-01-01T00:00:00Z').max('2970-12-31T23:59:59Z')
|
||||
)
|
||||
.length(2)
|
||||
.asc(),
|
||||
Joi.string().trim().valid('')
|
||||
);
|
||||
|
||||
const joiLabels = Joi.alternatives().try(
|
||||
extendedJoi
|
||||
.stringList()
|
||||
.items(Joi.string().trim().max(50))
|
||||
.min(1)
|
||||
.max(30)
|
||||
.unique(),
|
||||
Joi.string().trim().valid('')
|
||||
);
|
||||
|
||||
const schema = Joi.object({
|
||||
'github-token': Joi.string().trim().max(100),
|
||||
|
||||
'issue-lock-inactive-days': Joi.number()
|
||||
'issue-inactive-days': Joi.number()
|
||||
.min(0)
|
||||
.max(3650)
|
||||
.precision(9)
|
||||
.default(365),
|
||||
|
||||
'issue-exclude-created-before': Joi.alternatives()
|
||||
.try(
|
||||
Joi.date()
|
||||
// .iso()
|
||||
.min('1970-01-01T00:00:00Z')
|
||||
.max('2970-12-31T23:59:59Z'),
|
||||
Joi.string().trim().valid('')
|
||||
)
|
||||
.default(''),
|
||||
'exclude-issue-created-before': joiDate.default(''),
|
||||
|
||||
'issue-exclude-labels': Joi.alternatives()
|
||||
.try(
|
||||
extendedJoi
|
||||
.stringList()
|
||||
.items(Joi.string().trim().max(50))
|
||||
.min(1)
|
||||
.max(30)
|
||||
.unique(),
|
||||
Joi.string().trim().valid('')
|
||||
)
|
||||
.default(''),
|
||||
'exclude-issue-created-after': joiDate.default(''),
|
||||
|
||||
'issue-lock-labels': Joi.alternatives()
|
||||
.try(
|
||||
extendedJoi
|
||||
.stringList()
|
||||
.items(Joi.string().trim().max(50))
|
||||
.min(1)
|
||||
.max(30)
|
||||
.unique(),
|
||||
Joi.string().trim().valid('')
|
||||
)
|
||||
.default(''),
|
||||
'exclude-issue-created-between': joiTimeInterval.default(''),
|
||||
|
||||
'issue-lock-comment': Joi.string().trim().max(10000).allow('').default(''),
|
||||
'exclude-issue-closed-before': joiDate.default(''),
|
||||
|
||||
'exclude-issue-closed-after': joiDate.default(''),
|
||||
|
||||
'exclude-issue-closed-between': joiTimeInterval.default(''),
|
||||
|
||||
'include-any-issue-labels': joiLabels.default(''),
|
||||
|
||||
'include-all-issue-labels': joiLabels.default(''),
|
||||
|
||||
'exclude-any-issue-labels': joiLabels.default(''),
|
||||
|
||||
'add-issue-labels': joiLabels.default(''),
|
||||
|
||||
'remove-issue-labels': joiLabels.default(''),
|
||||
|
||||
'issue-comment': Joi.string().trim().max(10000).allow('').default(''),
|
||||
|
||||
'issue-lock-reason': Joi.string()
|
||||
.valid('resolved', 'off-topic', 'too heated', 'spam', '')
|
||||
.default('resolved'),
|
||||
|
||||
'pr-lock-inactive-days': Joi.number()
|
||||
.min(0)
|
||||
.max(3650)
|
||||
.precision(9)
|
||||
.default(365),
|
||||
'pr-inactive-days': Joi.number().min(0).max(3650).precision(9).default(365),
|
||||
|
||||
'pr-exclude-created-before': Joi.alternatives()
|
||||
.try(
|
||||
Joi.date()
|
||||
// .iso()
|
||||
.min('1970-01-01T00:00:00Z')
|
||||
.max('2970-12-31T23:59:59Z'),
|
||||
Joi.string().trim().valid('')
|
||||
)
|
||||
.default(''),
|
||||
'exclude-pr-created-before': joiDate.default(''),
|
||||
|
||||
'pr-exclude-labels': Joi.alternatives()
|
||||
.try(
|
||||
extendedJoi
|
||||
.stringList()
|
||||
.items(Joi.string().trim().max(50))
|
||||
.min(1)
|
||||
.max(30)
|
||||
.unique(),
|
||||
Joi.string().trim().valid('')
|
||||
)
|
||||
.default(''),
|
||||
'exclude-pr-created-after': joiDate.default(''),
|
||||
|
||||
'pr-lock-labels': Joi.alternatives()
|
||||
.try(
|
||||
extendedJoi
|
||||
.stringList()
|
||||
.items(Joi.string().trim().max(50))
|
||||
.min(1)
|
||||
.max(30)
|
||||
.unique(),
|
||||
Joi.string().trim().valid('')
|
||||
)
|
||||
.default(''),
|
||||
'exclude-pr-created-between': joiTimeInterval.default(''),
|
||||
|
||||
'pr-lock-comment': Joi.string().trim().max(10000).allow('').default(''),
|
||||
'exclude-pr-closed-before': joiDate.default(''),
|
||||
|
||||
'exclude-pr-closed-after': joiDate.default(''),
|
||||
|
||||
'exclude-pr-closed-between': joiTimeInterval.default(''),
|
||||
|
||||
'include-any-pr-labels': joiLabels.default(''),
|
||||
|
||||
'include-all-pr-labels': joiLabels.default(''),
|
||||
|
||||
'exclude-any-pr-labels': joiLabels.default(''),
|
||||
|
||||
'add-pr-labels': joiLabels.default(''),
|
||||
|
||||
'remove-pr-labels': joiLabels.default(''),
|
||||
|
||||
'pr-comment': Joi.string().trim().max(10000).allow('').default(''),
|
||||
|
||||
'pr-lock-reason': Joi.string()
|
||||
.valid('resolved', 'off-topic', 'too heated', 'spam', '')
|
||||
.default('resolved'),
|
||||
|
||||
'process-only': extendedJoi.processOnly().valid('issue', 'pr', '').default('')
|
||||
'process-only': extendedJoi
|
||||
.processOnly()
|
||||
.valid('issue', 'pr', '')
|
||||
.default(''),
|
||||
|
||||
'log-output': Joi.boolean().default(false)
|
||||
});
|
||||
|
||||
module.exports = schema;
|
||||
|
||||
Reference in New Issue
Block a user