Skip to content
This repository was archived by the owner on Nov 14, 2025. It is now read-only.

Commit cf9356b

Browse files
authored
Add new issue triager action with configurable assignees (#331)
1 parent 8045f13 commit cf9356b

File tree

3 files changed

+160
-0
lines changed

3 files changed

+160
-0
lines changed

triage/action.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: New Issue Triager
2+
description: Triage new issues to one of the assignees from the provided list
3+
inputs:
4+
token:
5+
description: 'GitHub token with issue, comment, and label read/write permissions'
6+
app_id:
7+
description: GitHub App ID
8+
required: true
9+
app_installation_id:
10+
description: GitHub App Installation ID
11+
required: true
12+
app_private_key:
13+
description: GitHub App Private Key
14+
required: true
15+
owner:
16+
description: Repository owner
17+
required: true
18+
repo:
19+
description: Repository name
20+
required: true
21+
issue_number:
22+
description: Issue number
23+
required: true
24+
event:
25+
description: Event name for a triggered action. Otherwise, this is obtained from the GitHub context.
26+
required: true
27+
action:
28+
description: Action name for a triggered action. Otherwise, this is obtained from the GitHub context.
29+
required: true
30+
assignees:
31+
description: Pipe-separated list of assignees to triage new issues to
32+
required: true
33+
runs:
34+
using: 'node20'
35+
main: 'index.js'

triage/index.js

Lines changed: 60 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

triage/index.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { OctoKitIssue } from '../api/octokit';
7+
import { VSCodeToolsAPIManager } from '../api/vscodeTools';
8+
import { Action } from '../common/Action';
9+
import { getRequiredInput, safeLog } from '../common/utils';
10+
11+
class IssueTriageAction extends Action {
12+
id = 'IssueTriageAction';
13+
14+
private async triage(issue: OctoKitIssue) {
15+
try {
16+
const githubIssue = await issue.getIssue();
17+
18+
// check to see that issue is not already assigned and that it does not have the triage-needed label
19+
if (githubIssue.assignees.length > 0 || githubIssue.labels.length > 0) {
20+
return;
21+
}
22+
23+
await issue.addLabel('triage-needed');
24+
const assignees: string[] = getRequiredInput('assignees').split('|');
25+
26+
if (assignees.length === 0) {
27+
safeLog('No assignees provided');
28+
return;
29+
}
30+
31+
const vscodeToolsAPI = new VSCodeToolsAPIManager();
32+
const triagers = await vscodeToolsAPI.getTriagerGitHubIds();
33+
34+
if (triagers.length === 0) {
35+
safeLog('No available triagers found');
36+
return;
37+
}
38+
39+
const available = assignees.filter((assignee) => triagers.includes(assignee));
40+
if (available) {
41+
// Shuffle the array
42+
for (let i = available.length - 1; i > 0; i--) {
43+
const j = Math.floor(Math.random() * (i + 1));
44+
[available[i], available[j]] = [available[j], available[i]];
45+
}
46+
47+
const randomSelection = available[0];
48+
safeLog('assigning', randomSelection);
49+
await issue.addAssignee(randomSelection);
50+
} else {
51+
safeLog('No available triagers');
52+
}
53+
} catch (e) {
54+
safeLog('Error assigning random triager', (e as any).message);
55+
}
56+
}
57+
58+
protected override async onOpened(issue: OctoKitIssue): Promise<void> {
59+
// wait 30 seconds before triaging
60+
await new Promise((resolve) => setTimeout(resolve, 30000));
61+
await this.triage(issue);
62+
}
63+
}
64+
65+
new IssueTriageAction().run(); // eslint-disable-line

0 commit comments

Comments
 (0)