mirror of
https://github.com/dessant/label-actions.git
synced 2026-03-13 01:27:03 -04:00
66
README.md
66
README.md
@@ -1,7 +1,7 @@
|
||||
# Label Actions
|
||||
|
||||
Label Actions is a GitHub bot that performs certain actions when issues
|
||||
or pull requests are labeled or unlabeled.
|
||||
Label Actions is a GitHub bot that performs certain actions when issues,
|
||||
pull requests or discussions are labeled or unlabeled.
|
||||
|
||||
<img width="800" src="https://raw.githubusercontent.com/dessant/label-actions/master/assets/screenshot.png">
|
||||
|
||||
@@ -16,7 +16,7 @@ please consider contributing with
|
||||
|
||||
## How It Works
|
||||
|
||||
The bot performs certain actions when an issue or pull request
|
||||
The bot performs certain actions when an issue, pull request or discussion
|
||||
is labeled or unlabeled. No action is taken by default and the bot
|
||||
must be configured. The following actions are supported:
|
||||
|
||||
@@ -34,7 +34,7 @@ must be configured. The following actions are supported:
|
||||
use one of the [example workflows](#examples) to get started
|
||||
2. Create the `.github/label-actions.yml` configuration file
|
||||
based on the [example](#configuring-labels-and-actions) below
|
||||
3. Start labeling issues and pull requests
|
||||
3. Start labeling issues, pull requests and discussions
|
||||
|
||||
### Inputs
|
||||
|
||||
@@ -49,8 +49,9 @@ The bot can be configured using [input parameters](https://docs.github.com/en/ac
|
||||
- Configuration file path
|
||||
- Optional, defaults to `.github/label-actions.yml`
|
||||
- **`process-only`**
|
||||
- Process label events only for issues or pull requests, value must be
|
||||
either `issues` or `prs`
|
||||
- Process label events only for issues, pull requests or discussions,
|
||||
value must be a comma separated list, list items must be
|
||||
one of `issues`, `prs` or `discussions`
|
||||
- Optional, defaults to `''`
|
||||
|
||||
### Configuration
|
||||
@@ -58,8 +59,9 @@ The bot can be configured using [input parameters](https://docs.github.com/en/ac
|
||||
Labels and actions are specified in a configuration file.
|
||||
Actions are grouped under label names, and a label name can be prepended
|
||||
with a `-` sign to declare actions taken when a label is removed
|
||||
from a thread. Actions can be overridden or declared only for issues
|
||||
or pull requests by grouping them under the `issues` or `prs` key.
|
||||
from a thread. Actions can be overridden or declared only for issues,
|
||||
pull requests or discussions by grouping them under the
|
||||
`issues`, `prs` or `discussions` key.
|
||||
|
||||
#### Actions
|
||||
|
||||
@@ -75,17 +77,20 @@ or pull requests by grouping them under the `issues` or `prs` key.
|
||||
- Remove labels, value must be either a label or a list of labels
|
||||
- Optional, defaults to `''`
|
||||
- **`close`**
|
||||
- Close threads, value must be either `true` or `false`
|
||||
- Close threads, value must be either `true` or `false`,
|
||||
ignored for discussions
|
||||
- Optional, defaults to `false`
|
||||
- **`reopen`**
|
||||
- Reopen threads, value must be either `true` or `false`
|
||||
- Reopen threads, value must be either `true` or `false`,
|
||||
ignored for discussions
|
||||
- Optional, defaults to `false`
|
||||
- **`lock`**
|
||||
- Lock threads, value must be either `true` or `false`
|
||||
- Optional, defaults to `false`
|
||||
- **`lock-reason`**
|
||||
- Reason for locking threads, value must be one
|
||||
of `resolved`, `off-topic`, `too heated` or `spam`
|
||||
of `resolved`, `off-topic`, `too heated` or `spam`,
|
||||
ignored for discussions
|
||||
- Optional, defaults to `''`
|
||||
- **`unlock`**
|
||||
- Unlock threads, value must be either `true` or `false`
|
||||
@@ -94,8 +99,8 @@ or pull requests by grouping them under the `issues` or `prs` key.
|
||||
## Examples
|
||||
|
||||
The following workflow will perform the actions specified
|
||||
in the `.github/label-actions.yml` configuration file when an issue
|
||||
or pull request is labeled or unlabeled.
|
||||
in the `.github/label-actions.yml` configuration file when an issue,
|
||||
pull request or discussion is labeled or unlabeled.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```yaml
|
||||
@@ -106,11 +111,14 @@ on:
|
||||
types: [labeled, unlabeled]
|
||||
pull_request:
|
||||
types: [labeled, unlabeled]
|
||||
discussion:
|
||||
types: [labeled, unlabeled]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
discussions: write
|
||||
|
||||
jobs:
|
||||
action:
|
||||
@@ -133,11 +141,14 @@ on:
|
||||
types: [labeled, unlabeled]
|
||||
pull_request:
|
||||
types: [labeled, unlabeled]
|
||||
discussion:
|
||||
types: [labeled, unlabeled]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
discussions: write
|
||||
|
||||
jobs:
|
||||
action:
|
||||
@@ -162,14 +173,14 @@ This step will process label events only for issues.
|
||||
process-only: 'issues'
|
||||
```
|
||||
|
||||
This step will process label events only for pull requests.
|
||||
This step will process label events only for pull requests and discussions.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```yaml
|
||||
steps:
|
||||
- uses: dessant/label-actions@v2
|
||||
with:
|
||||
process-only: 'prs'
|
||||
process-only: 'prs, discussions'
|
||||
```
|
||||
|
||||
Unnecessary workflow runs can be avoided by removing the events
|
||||
@@ -191,7 +202,7 @@ The following example showcases how desired actions may be declared:
|
||||
```yaml
|
||||
# Configuration for Label Actions - https://github.com/dessant/label-actions
|
||||
|
||||
# Actions taken when the `heated` label is added to issues or pull requests
|
||||
# The `heated` label is added to issues, pull requests or discussions
|
||||
heated:
|
||||
# Post a comment
|
||||
comment: >
|
||||
@@ -205,17 +216,18 @@ heated:
|
||||
prs:
|
||||
label: 'on hold'
|
||||
|
||||
# Actions taken when the `heated` label is removed from issues or pull requests
|
||||
# The `heated` label is removed from issues, pull requests or discussions
|
||||
-heated:
|
||||
# Unlock the thread
|
||||
unlock: true
|
||||
|
||||
# Actions taken when the `wontfix` label is removed from issues or pull requests
|
||||
# The `wontfix` label is removed from issues
|
||||
-wontfix:
|
||||
# Reopen the thread
|
||||
reopen: true
|
||||
issues:
|
||||
# Reopen the issue
|
||||
reopen: true
|
||||
|
||||
# Actions taken when the `feature` label is added to issues
|
||||
# The `feature` label is added to issues
|
||||
feature:
|
||||
issues:
|
||||
# Post a comment, `{issue-author}` is an optional placeholder
|
||||
@@ -224,7 +236,7 @@ feature:
|
||||
# Close the issue
|
||||
close: true
|
||||
|
||||
# Actions taken when the `wip` label is added to pull requests
|
||||
# The `wip` label is added to pull requests
|
||||
wip:
|
||||
prs:
|
||||
# Add labels
|
||||
@@ -232,7 +244,7 @@ wip:
|
||||
- 'on hold'
|
||||
- 'needs feedback'
|
||||
|
||||
# Actions taken when the `wip` label is removed from pull requests
|
||||
# The `wip` label is removed from pull requests
|
||||
-wip:
|
||||
prs:
|
||||
# Add label
|
||||
@@ -242,7 +254,13 @@ wip:
|
||||
- 'on hold'
|
||||
- 'needs feedback'
|
||||
|
||||
# Actions taken when the `pizzazz` label is added to issues or pull requests
|
||||
# The `solved` label is added to discussions
|
||||
solved:
|
||||
discussions:
|
||||
# Lock the discussion
|
||||
lock: true
|
||||
|
||||
# The `pizzazz` label is added to issues, pull requests or discussions
|
||||
pizzazz:
|
||||
# Post comments
|
||||
comment:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: 'Label Actions'
|
||||
description: 'Perform actions when issues or pull requests are labeled or unlabeled'
|
||||
description: 'Perform actions when issues, pull requests or discussions are labeled or unlabeled'
|
||||
author: 'Armin Sebastian'
|
||||
inputs:
|
||||
github-token:
|
||||
@@ -9,7 +9,7 @@ inputs:
|
||||
description: 'Configuration file path'
|
||||
default: '.github/label-actions.yml'
|
||||
process-only:
|
||||
description: 'Process label events only for issues or pull requests, value must be either `issues` or `prs`'
|
||||
description: 'Process label events only for issues, pull requests or discussions, value must be a comma separated list, list items must be one of `issues`, `prs` or `discussions`'
|
||||
default: ''
|
||||
runs:
|
||||
using: 'node12'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "label-actions",
|
||||
"version": "2.1.3",
|
||||
"description": "A GitHub Action that performs actions when issues or pull requests are labeled or unlabeled.",
|
||||
"description": "A GitHub Action that performs actions when issues, pull requests or discussions are labeled or unlabeled.",
|
||||
"author": "Armin Sebastian",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/dessant/label-actions",
|
||||
@@ -38,6 +38,7 @@
|
||||
"github",
|
||||
"issues",
|
||||
"pull requests",
|
||||
"discussions",
|
||||
"github labels",
|
||||
"comment",
|
||||
"close",
|
||||
|
||||
110
src/data.js
Normal file
110
src/data.js
Normal file
@@ -0,0 +1,110 @@
|
||||
const addDiscussionCommentQuery = `
|
||||
mutation ($discussionId: ID!, $body: String!) {
|
||||
addDiscussionComment(input: {discussionId: $discussionId, body: $body}) {
|
||||
comment {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const getLabelQuery = `
|
||||
query ($owner: String!, $repo: String!, $label: String!) {
|
||||
repository(owner: $owner, name: $repo) {
|
||||
label(name: $label) {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const createLabelQuery = `
|
||||
mutation ($repositoryId: ID!, $name: String!, $color: String!) {
|
||||
createLabel(input: {repositoryId: $repositoryId, name: $name, , color: $color}) {
|
||||
label {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const getDiscussionLabelsQuery = `
|
||||
query ($owner: String!, $repo: String!, $discussion: Int!) {
|
||||
repository(owner: $owner, name: $repo) {
|
||||
discussion(number: $discussion) {
|
||||
number
|
||||
labels(first: 100) {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const addLabelsToLabelableQuery = `
|
||||
mutation ($labelableId: ID!, $labelIds: [ID!]!) {
|
||||
addLabelsToLabelable(input: {labelableId: $labelableId, labelIds: $labelIds}) {
|
||||
labelable {
|
||||
labels(first: 0) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const removeLabelsFromLabelableQuery = `
|
||||
mutation ($labelableId: ID!, $labelIds: [ID!]!) {
|
||||
removeLabelsFromLabelable(input: {labelableId: $labelableId, labelIds: $labelIds}) {
|
||||
labelable {
|
||||
labels(first: 0) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const lockLockableQuery = `
|
||||
mutation ($lockableId: ID!) {
|
||||
lockLockable(input: {lockableId: $lockableId}) {
|
||||
lockedRecord {
|
||||
locked
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const unlockLockableQuery = `
|
||||
mutation ($lockableId: ID!) {
|
||||
unlockLockable(input: {lockableId: $lockableId}) {
|
||||
unlockedRecord {
|
||||
locked
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
module.exports = {
|
||||
addDiscussionCommentQuery,
|
||||
getLabelQuery,
|
||||
createLabelQuery,
|
||||
getDiscussionLabelsQuery,
|
||||
addLabelsToLabelableQuery,
|
||||
removeLabelsFromLabelableQuery,
|
||||
lockLockableQuery,
|
||||
unlockLockableQuery
|
||||
};
|
||||
271
src/index.js
271
src/index.js
@@ -3,6 +3,16 @@ const github = require('@actions/github');
|
||||
const yaml = require('js-yaml');
|
||||
|
||||
const {configSchema, actionSchema} = require('./schema');
|
||||
const {
|
||||
addDiscussionCommentQuery,
|
||||
getLabelQuery,
|
||||
createLabelQuery,
|
||||
getDiscussionLabelsQuery,
|
||||
addLabelsToLabelableQuery,
|
||||
removeLabelsFromLabelableQuery,
|
||||
lockLockableQuery,
|
||||
unlockLockableQuery
|
||||
} = require('./data');
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
@@ -33,10 +43,14 @@ class App {
|
||||
return;
|
||||
}
|
||||
|
||||
const threadType = payload.issue ? 'issue' : 'pr';
|
||||
const [threadType, threadData] = payload.issue
|
||||
? ['issue', payload.issue]
|
||||
: payload.pull_request
|
||||
? ['pr', payload.pull_request]
|
||||
: ['discussion', payload.discussion];
|
||||
|
||||
const processOnly = this.config['process-only'];
|
||||
if (processOnly && processOnly !== threadType) {
|
||||
if (processOnly && !processOnly.includes(threadType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,10 +63,20 @@ class App {
|
||||
return;
|
||||
}
|
||||
|
||||
const threadData = payload.issue || payload.pull_request;
|
||||
|
||||
const {owner, repo} = github.context.repo;
|
||||
const issue = {owner, repo, issue_number: threadData.number};
|
||||
let issue, discussion;
|
||||
if (threadType === 'discussion') {
|
||||
discussion = {
|
||||
node_id: payload.discussion.node_id,
|
||||
number: payload.discussion.number
|
||||
};
|
||||
} else {
|
||||
issue = {
|
||||
owner,
|
||||
repo,
|
||||
issue_number: threadData.number
|
||||
};
|
||||
}
|
||||
|
||||
const lock = {
|
||||
active: threadData.locked,
|
||||
@@ -61,79 +85,164 @@ class App {
|
||||
|
||||
if (actions.comment) {
|
||||
core.debug('Commenting');
|
||||
await this.ensureUnlock(issue, lock, async () => {
|
||||
await this.ensureUnlock({issue, discussion}, lock, async () => {
|
||||
for (let commentBody of actions.comment) {
|
||||
commentBody = commentBody.replace(
|
||||
/{issue-author}/,
|
||||
threadData.user.login
|
||||
);
|
||||
|
||||
await this.client.rest.issues.createComment({
|
||||
...issue,
|
||||
body: commentBody
|
||||
});
|
||||
if (threadType === 'discussion') {
|
||||
await this.client.graphql(addDiscussionCommentQuery, {
|
||||
discussionId: discussion.node_id,
|
||||
body: commentBody
|
||||
});
|
||||
} else {
|
||||
await this.client.rest.issues.createComment({
|
||||
...issue,
|
||||
body: commentBody
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (actions.label) {
|
||||
const currentLabels = threadData.labels.map(label => label.name);
|
||||
const newLabels = actions.label.filter(
|
||||
label => !currentLabels.includes(label)
|
||||
);
|
||||
if (actions.label || actions.unlabel) {
|
||||
let currentLabels;
|
||||
if (threadType === 'discussion') {
|
||||
({
|
||||
repository: {
|
||||
discussion: {
|
||||
labels: {nodes: currentLabels}
|
||||
}
|
||||
}
|
||||
} = await this.client.graphql(getDiscussionLabelsQuery, {
|
||||
owner,
|
||||
repo,
|
||||
discussion: discussion.number
|
||||
}));
|
||||
} else {
|
||||
currentLabels = threadData.labels;
|
||||
}
|
||||
|
||||
if (newLabels.length) {
|
||||
core.debug('Labeling');
|
||||
await this.client.rest.issues.addLabels({
|
||||
...issue,
|
||||
labels: newLabels
|
||||
});
|
||||
if (actions.label) {
|
||||
const currentLabelNames = currentLabels.map(label => label.name);
|
||||
const newLabels = actions.label.filter(
|
||||
label => !currentLabelNames.includes(label)
|
||||
);
|
||||
|
||||
if (newLabels.length) {
|
||||
core.debug('Labeling');
|
||||
|
||||
if (threadType === 'discussion') {
|
||||
const labels = [];
|
||||
for (const labelName of newLabels) {
|
||||
let {
|
||||
repository: {label}
|
||||
} = await this.client.graphql(getLabelQuery, {
|
||||
owner,
|
||||
repo,
|
||||
label: labelName
|
||||
});
|
||||
|
||||
if (!label) {
|
||||
({
|
||||
createLabel: {label}
|
||||
} = await this.client.graphql(createLabelQuery, {
|
||||
repositoryId: payload.repository.node_id,
|
||||
name: labelName,
|
||||
color: 'ffffff',
|
||||
headers: {Accept: 'application/vnd.github.bane-preview+json'}
|
||||
}));
|
||||
}
|
||||
|
||||
labels.push(label);
|
||||
}
|
||||
|
||||
await this.client.graphql(addLabelsToLabelableQuery, {
|
||||
labelableId: discussion.node_id,
|
||||
labelIds: labels.map(label => label.id)
|
||||
});
|
||||
} else {
|
||||
await this.client.rest.issues.addLabels({
|
||||
...issue,
|
||||
labels: newLabels
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (actions.unlabel) {
|
||||
const matchingLabels = currentLabels.filter(label =>
|
||||
actions.unlabel.includes(label.name)
|
||||
);
|
||||
|
||||
if (matchingLabels.length) {
|
||||
core.debug('Unlabeling');
|
||||
|
||||
if (threadType === 'discussion') {
|
||||
await this.client.graphql(removeLabelsFromLabelableQuery, {
|
||||
labelableId: discussion.node_id,
|
||||
labelIds: matchingLabels.map(label => label.id)
|
||||
});
|
||||
} else {
|
||||
for (const label of matchingLabels) {
|
||||
await this.client.rest.issues.removeLabel({
|
||||
...issue,
|
||||
name: label.name
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (actions.unlabel) {
|
||||
const currentLabels = threadData.labels.map(label => label.name);
|
||||
const matchingLabels = currentLabels.filter(label =>
|
||||
actions.unlabel.includes(label)
|
||||
);
|
||||
|
||||
for (const label of matchingLabels) {
|
||||
core.debug('Unlabeling');
|
||||
await this.client.rest.issues.removeLabel({
|
||||
...issue,
|
||||
name: label
|
||||
});
|
||||
if (threadType !== 'discussion') {
|
||||
if (
|
||||
actions.reopen &&
|
||||
threadData.state === 'closed' &&
|
||||
!threadData.merged
|
||||
) {
|
||||
core.debug('Reopening');
|
||||
await this.client.rest.issues.update({...issue, state: 'open'});
|
||||
}
|
||||
}
|
||||
|
||||
if (actions.reopen && threadData.state === 'closed' && !threadData.merged) {
|
||||
core.debug('Reopening');
|
||||
await this.client.rest.issues.update({...issue, state: 'open'});
|
||||
}
|
||||
|
||||
if (actions.close && threadData.state === 'open') {
|
||||
core.debug('Closing');
|
||||
await this.client.rest.issues.update({...issue, state: 'closed'});
|
||||
if (actions.close && threadData.state === 'open') {
|
||||
core.debug('Closing');
|
||||
await this.client.rest.issues.update({...issue, state: 'closed'});
|
||||
}
|
||||
}
|
||||
|
||||
if (actions.lock && !threadData.locked) {
|
||||
core.debug('Locking');
|
||||
const params = {...issue};
|
||||
const lockReason = actions['lock-reason'];
|
||||
if (lockReason) {
|
||||
Object.assign(params, {
|
||||
lock_reason: lockReason,
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.sailor-v-preview+json'
|
||||
}
|
||||
if (threadType === 'discussion') {
|
||||
await this.client.graphql(lockLockableQuery, {
|
||||
lockableId: discussion.node_id
|
||||
});
|
||||
} else {
|
||||
const params = {...issue};
|
||||
const lockReason = actions['lock-reason'];
|
||||
if (lockReason) {
|
||||
Object.assign(params, {
|
||||
lock_reason: lockReason,
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.sailor-v-preview+json'
|
||||
}
|
||||
});
|
||||
}
|
||||
await this.client.rest.issues.lock(params);
|
||||
}
|
||||
await this.client.rest.issues.lock(params);
|
||||
}
|
||||
|
||||
if (actions.unlock && threadData.locked) {
|
||||
core.debug('Unlocking');
|
||||
await this.client.rest.issues.unlock(issue);
|
||||
if (threadType === 'discussion') {
|
||||
await this.client.graphql(unlockLockableQuery, {
|
||||
lockableId: discussion.node_id
|
||||
});
|
||||
} else {
|
||||
await this.client.rest.issues.unlock(issue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +250,13 @@ class App {
|
||||
if (event === 'unlabeled') {
|
||||
label = `-${label}`;
|
||||
}
|
||||
threadType = threadType === 'issue' ? 'issues' : 'prs';
|
||||
|
||||
threadType =
|
||||
threadType === 'issue'
|
||||
? 'issues'
|
||||
: threadType === 'pr'
|
||||
? 'prs'
|
||||
: 'discussions';
|
||||
|
||||
const actions = this.actions[label];
|
||||
|
||||
@@ -155,18 +270,25 @@ class App {
|
||||
}
|
||||
}
|
||||
|
||||
async ensureUnlock(issue, lock, action) {
|
||||
async ensureUnlock({issue, discussion}, lock, action) {
|
||||
if (lock.active) {
|
||||
if (!lock.hasOwnProperty('reason')) {
|
||||
const {data: issueData} = await this.client.rest.issues.get({
|
||||
...issue,
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.sailor-v-preview+json'
|
||||
}
|
||||
if (issue) {
|
||||
if (!lock.hasOwnProperty('reason')) {
|
||||
const {data: issueData} = await this.client.rest.issues.get({
|
||||
...issue,
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.sailor-v-preview+json'
|
||||
}
|
||||
});
|
||||
lock.reason = issueData.active_lock_reason;
|
||||
}
|
||||
|
||||
await this.client.rest.issues.unlock(issue);
|
||||
} else {
|
||||
await this.client.graphql(unlockLockableQuery, {
|
||||
lockableId: discussion.node_id
|
||||
});
|
||||
lock.reason = issueData.active_lock_reason;
|
||||
}
|
||||
await this.client.rest.issues.unlock(issue);
|
||||
|
||||
let actionError;
|
||||
try {
|
||||
@@ -175,16 +297,23 @@ class App {
|
||||
actionError = err;
|
||||
}
|
||||
|
||||
if (lock.reason) {
|
||||
issue = {
|
||||
...issue,
|
||||
lock_reason: lock.reason,
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.sailor-v-preview+json'
|
||||
}
|
||||
};
|
||||
if (issue) {
|
||||
if (lock.reason) {
|
||||
issue = {
|
||||
...issue,
|
||||
lock_reason: lock.reason,
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.sailor-v-preview+json'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
await this.client.rest.issues.lock(issue);
|
||||
} else {
|
||||
await this.client.graphql(lockLockableQuery, {
|
||||
lockableId: discussion.node_id
|
||||
});
|
||||
}
|
||||
await this.client.rest.issues.lock(issue);
|
||||
|
||||
if (actionError) {
|
||||
throw actionError;
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
const Joi = require('joi');
|
||||
|
||||
const extendedJoi = Joi.extend({
|
||||
type: 'processOnly',
|
||||
base: Joi.string(),
|
||||
coerce: {
|
||||
from: 'string',
|
||||
method(value) {
|
||||
value = value.trim();
|
||||
if (['issues', 'prs'].includes(value)) {
|
||||
value = value.slice(0, -1);
|
||||
}
|
||||
const extendedJoi = Joi.extend(joi => {
|
||||
return {
|
||||
type: 'processOnly',
|
||||
base: joi.array(),
|
||||
coerce: {
|
||||
from: 'string',
|
||||
method(value) {
|
||||
value = value.trim();
|
||||
|
||||
return {value};
|
||||
if (value) {
|
||||
value = value
|
||||
.split(',')
|
||||
.map(item => {
|
||||
item = item.trim();
|
||||
if (['issues', 'prs', 'discussions'].includes(item)) {
|
||||
item = item.slice(0, -1);
|
||||
}
|
||||
return item;
|
||||
})
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
return {value};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const configSchema = Joi.object({
|
||||
@@ -24,7 +36,15 @@ const configSchema = Joi.object({
|
||||
.max(200)
|
||||
.default('.github/label-actions.yml'),
|
||||
|
||||
'process-only': extendedJoi.processOnly().valid('issue', 'pr', '').default('')
|
||||
'process-only': Joi.alternatives().try(
|
||||
extendedJoi
|
||||
.processOnly()
|
||||
.items(Joi.string().valid('issue', 'pr', 'discussion'))
|
||||
.min(1)
|
||||
.max(3)
|
||||
.unique(),
|
||||
Joi.string().trim().valid('')
|
||||
)
|
||||
});
|
||||
|
||||
const actions = {
|
||||
@@ -84,7 +104,8 @@ const actionSchema = Joi.object()
|
||||
unlabel: actions.unlabel.default(''),
|
||||
|
||||
issues: Joi.object().keys(actions),
|
||||
prs: Joi.object().keys(actions)
|
||||
prs: Joi.object().keys(actions),
|
||||
discussions: Joi.object().keys(actions)
|
||||
})
|
||||
)
|
||||
.min(1)
|
||||
|
||||
Reference in New Issue
Block a user