|
1 | 1 | import { Octokit } from '@octokit/rest'; |
2 | 2 |
|
| 3 | +import { DEFAULT_CONFIG } from './constants.mjs'; |
| 4 | + |
3 | 5 | /** |
4 | | - * Creates GitHub issue with meeting information and Google Doc link |
| 6 | + * Creates a GitHub API client |
5 | 7 | * @param {import('./types.d.ts').AppConfig} config - Application configuration |
| 8 | + * @returns {import('@octokit/rest').Octokit} Configured GitHub API client |
| 9 | + */ |
| 10 | +export const createGitHubClient = ({ githubToken: auth }) => |
| 11 | + new Octokit({ auth }); |
| 12 | + |
| 13 | +/** |
| 14 | + * Creates GitHub issue with meeting information and Google Doc link |
| 15 | + * @param {import('@octokit/rest').Octokit} githubClient - Authenticated GitHub API client |
6 | 16 | * @param {import('./types.d.ts').MeetingConfig} meetingConfig - Meeting configuration object |
7 | 17 | * @param {string} title - Issue title |
8 | 18 | * @param {string} content - Issue content |
9 | 19 | * @returns {Promise<GitHubIssue>} Created issue data |
10 | 20 | */ |
11 | 21 | export const createGitHubIssue = async ( |
12 | | - config, |
13 | | - meetingConfig, |
| 22 | + { rest }, |
| 23 | + { properties }, |
14 | 24 | title, |
15 | 25 | content |
16 | 26 | ) => { |
17 | | - // Initialize GitHub API client with authentication token |
18 | | - const octokit = new Octokit({ auth: config.githubToken }); |
| 27 | + const githubOrg = properties.USER ?? DEFAULT_CONFIG.githubOrg; |
19 | 28 |
|
20 | | - // Extract issue label from config, removing quotes if present |
21 | | - const issueLabel = meetingConfig.properties.ISSUE_LABEL; |
| 29 | + const issueLabel = properties.ISSUE_LABEL |
| 30 | + ? [properties.ISSUE_LABEL] |
| 31 | + : undefined; |
22 | 32 |
|
23 | 33 | // Create the GitHub issue with meeting information |
24 | | - const response = await octokit.rest.issues.create({ |
25 | | - // Repository information from meeting config |
26 | | - owner: meetingConfig.properties.USER, |
27 | | - repo: meetingConfig.properties.REPO, |
| 34 | + const response = await rest.issues.create({ |
| 35 | + owner: githubOrg, |
| 36 | + repo: properties.REPO, |
28 | 37 | title, |
29 | 38 | body: content, |
30 | | - // Add label if specified in config |
31 | | - labels: issueLabel ? [issueLabel] : undefined, |
| 39 | + labels: issueLabel, |
32 | 40 | }); |
33 | 41 |
|
34 | 42 | return response.data; |
35 | 43 | }; |
36 | 44 |
|
37 | 45 | /** |
38 | 46 | * Fetches GitHub issues from all repositories in an organization with a specific label |
39 | | - * @param {string} token - GitHub personal access token |
40 | | - * @param {string} org - GitHub organization name (e.g., 'nodejs') |
41 | | - * @param {string} label - Label to filter by (e.g., 'tsc-agenda') |
42 | | - * @returns {Promise<string>} Formatted markdown string of issues |
| 47 | + * @param {import('@octokit/rest').Octokit} githubClient - Authenticated GitHub API client |
| 48 | + * @param {import('./types.d.ts').AppConfig} config - Application configuration |
| 49 | + * @param {import('./types.d.ts').MeetingConfig} meetingConfig - Meeting configuration |
| 50 | + * @returns {Promise<{ repoName: string, issues: Array<GitHubIssue> }> } Formatted markdown string of issues |
43 | 51 | */ |
44 | | -export const fetchAgendaIssues = async (token, org, label) => { |
45 | | - const octokit = new Octokit({ auth: token }); |
| 52 | +export const getAgendaIssues = async ( |
| 53 | + { paginate, rest }, |
| 54 | + { meetingGroup }, |
| 55 | + { properties } |
| 56 | +) => { |
| 57 | + const githubOrg = properties.USER ?? DEFAULT_CONFIG.githubOrg; |
| 58 | + const agendaTag = properties.AGENDA_TAG ?? `${meetingGroup}-agenda`; |
46 | 59 |
|
47 | 60 | // Get all public repositories in the organization |
48 | | - const repos = await octokit.paginate(octokit.rest.repos.listForOrg, { |
49 | | - org, |
| 61 | + const repos = await paginate(rest.repos.listForOrg, { |
| 62 | + org: properties.USER, |
50 | 63 | type: 'public', |
51 | 64 | per_page: 100, |
52 | 65 | }); |
53 | 66 |
|
54 | 67 | // Fetch issues from all repositories concurrently |
55 | 68 | const issuePromises = repos.map(async repo => { |
56 | | - const issues = await octokit.paginate(octokit.rest.issues.listForRepo, { |
57 | | - owner: org, |
| 69 | + const issues = await paginate(rest.issues.listForRepo, { |
| 70 | + owner: githubOrg, |
58 | 71 | repo: repo.name, |
59 | | - labels: label, |
| 72 | + labels: agendaTag, |
60 | 73 | state: 'open', |
61 | 74 | per_page: 100, |
62 | 75 | }); |
63 | 76 |
|
64 | | - const filteredIssues = issues.filter(issue => !issue.pull_request); // Exclude PRs |
| 77 | + const filteredIssues = issues.filter(({ pull_request }) => !pull_request); // Exclude PRs |
65 | 78 |
|
66 | 79 | return { repoName: repo.name, issues: filteredIssues }; |
67 | 80 | }); |
68 | 81 |
|
69 | | - const repoIssues = await Promise.all(issuePromises); |
70 | | - |
71 | | - // Format issues as markdown |
72 | | - let agendaMarkdown = ''; |
73 | | - |
74 | | - repoIssues.forEach(({ repoName, issues }) => { |
75 | | - if (issues.length > 0) { |
76 | | - agendaMarkdown += `### ${org}/${repoName}\n\n`; |
77 | | - |
78 | | - issues.forEach(issue => { |
79 | | - // Escape markdown characters in title |
80 | | - const cleanTitle = issue.title.replace(/([[\]])/g, '\\$1'); |
81 | | - |
82 | | - agendaMarkdown += `* ${cleanTitle} [#${issue.number}](${issue.html_url})\n`; |
83 | | - }); |
84 | | - |
85 | | - agendaMarkdown += '\n'; |
86 | | - } |
87 | | - }); |
88 | | - |
89 | | - return agendaMarkdown.trim(); |
| 82 | + return Promise.all(issuePromises); |
90 | 83 | }; |
0 commit comments