Skip to content

Commit 2249b2a

Browse files
committed
Add script to create GitHub issues assigned to Copilot and update workflow to use it
1 parent c2ec4ab commit 2249b2a

File tree

2 files changed

+138
-0
lines changed

2 files changed

+138
-0
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { Octokit } from '@octokit/rest';
2+
3+
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
4+
const GITHUB_REPO_OWNER = process.env.GITHUB_REPO_OWNER;
5+
const GITHUB_REPO_NAME = process.env.GITHUB_REPO_NAME;
6+
7+
/**
8+
* Creates a GitHub issue from the provided description and assigns it to @copilot-swe-agent if available.
9+
* Uses GraphQL for efficient repo/actor queries and issue creation with assignment.
10+
* Returns the issue URL on success, null on failure.
11+
*/
12+
export async function createIssueWithCopilot(description: string): Promise<string | null> {
13+
if (!GITHUB_TOKEN || !GITHUB_REPO_OWNER || !GITHUB_REPO_NAME) {
14+
return null;
15+
}
16+
17+
if (!description.trim()) {
18+
return null;
19+
}
20+
21+
const octokit = new Octokit({ auth: GITHUB_TOKEN });
22+
23+
try {
24+
// Fetch repo ID and check for @copilot-swe-agent
25+
const repoInfoQuery = `
26+
query($owner: String!, $name: String!) {
27+
repository(owner: $owner, name: $name) {
28+
id
29+
suggestedActors(capabilities: [CAN_BE_ASSIGNED], first: 100) {
30+
nodes {
31+
login
32+
id
33+
}
34+
}
35+
}
36+
}
37+
`;
38+
39+
const repoInfo: any = await octokit.graphql(repoInfoQuery, {
40+
owner: GITHUB_REPO_OWNER,
41+
name: GITHUB_REPO_NAME,
42+
});
43+
44+
const repoId = repoInfo?.repository?.id;
45+
if (!repoId) {
46+
return null;
47+
}
48+
49+
const copilotBot = repoInfo.repository.suggestedActors.nodes.find(
50+
(node: any) => node.login === 'copilot-swe-agent'
51+
);
52+
53+
const title = description.split('\n')[0].slice(0, 100);
54+
55+
if (!copilotBot) {
56+
// Fallback: Create issue without assignment via REST
57+
const issue = await octokit.issues.create({
58+
owner: GITHUB_REPO_OWNER,
59+
repo: GITHUB_REPO_NAME,
60+
title,
61+
body: description,
62+
});
63+
64+
return issue.data.html_url;
65+
}
66+
67+
// Create issue with assignment via GraphQL
68+
const createIssueMutation = `
69+
mutation($repoId: ID!, $title: String!, $body: String!, $assigneeIds: [ID!]) {
70+
createIssue(input: { repositoryId: $repoId, title: $title, body: $body, assigneeIds: $assigneeIds }) {
71+
issue {
72+
number
73+
title
74+
url
75+
assignees(first: 10) { nodes { login } }
76+
}
77+
}
78+
}
79+
`;
80+
81+
const response: any = await octokit.graphql(createIssueMutation, {
82+
repoId,
83+
title,
84+
body: description,
85+
assigneeIds: [copilotBot.id],
86+
});
87+
88+
const issue = response?.createIssue?.issue;
89+
if (!issue) {
90+
return null;
91+
}
92+
93+
return issue.url;
94+
} catch (error) {
95+
console.error('Error creating issue:', error);
96+
return null;
97+
}
98+
}
99+
100+
// CLI entry point
101+
const description = process.argv[2];
102+
if (!description) {
103+
console.error('Usage: npx tsx create-issue-assigned-to-copilot.py <description>');
104+
process.exit(1);
105+
}
106+
createIssueWithCopilot(description).then((url) => {
107+
if (url) {
108+
console.log(`Issue created: ${url}`);
109+
} else {
110+
console.error('Failed to create issue');
111+
process.exit(1);
112+
}
113+
});

.github/workflows/copilot-issue.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,28 @@ jobs:
2525
assignees: ['copilot-swe-agent']
2626
});
2727
core.notice(`Created issue #${issue.data.number}: ${issue.data.html_url}`);
28+
29+
create-issue-graphql:
30+
runs-on: ubuntu-latest
31+
permissions:
32+
issues: write
33+
steps:
34+
- name: Checkout repository
35+
uses: actions/checkout@v6
36+
37+
- name: Setup Node.js
38+
uses: actions/setup-node@v6
39+
with:
40+
node-version: '22'
41+
42+
- name: Install dependencies
43+
run: npm install @octokit/rest tsx
44+
working-directory: .github/scripts
45+
46+
- name: Create issue via GraphQL
47+
env:
48+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
49+
GITHUB_REPO_OWNER: ${{ github.repository_owner }}
50+
GITHUB_REPO_NAME: ${{ github.event.repository.name }}
51+
run: npx tsx create-issue-assigned-to-copilot.py "${{ inputs.title }}"
52+
working-directory: .github/scripts

0 commit comments

Comments
 (0)