gh-load-pull-request 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -5
- package/package.json +1 -1
- package/src/backends.mjs +495 -0
- package/src/formatters.mjs +245 -0
- package/src/gh-load-pull-request.mjs +477 -474
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatters for gh-load-pull-request
|
|
3
|
+
* Contains functions for converting PR data to markdown and JSON formats
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Format a date string for display
|
|
8
|
+
* @param {string} dateStr - ISO date string
|
|
9
|
+
* @returns {string} Formatted date string
|
|
10
|
+
*/
|
|
11
|
+
export function formatDate(dateStr) {
|
|
12
|
+
if (!dateStr) {
|
|
13
|
+
return '';
|
|
14
|
+
}
|
|
15
|
+
const date = new Date(dateStr);
|
|
16
|
+
return date
|
|
17
|
+
.toISOString()
|
|
18
|
+
.replace('T', ' ')
|
|
19
|
+
.replace(/\.\d+Z$/, ' UTC');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Convert PR data to JSON format
|
|
24
|
+
* @param {Object} data - PR data from loadPullRequest
|
|
25
|
+
* @param {Array} downloadedImages - Array of downloaded image info
|
|
26
|
+
* @returns {string} JSON string
|
|
27
|
+
*/
|
|
28
|
+
export function convertToJson(data, downloadedImages = []) {
|
|
29
|
+
const { pr, files, comments, reviewComments, reviews, commits } = data;
|
|
30
|
+
|
|
31
|
+
return JSON.stringify(
|
|
32
|
+
{
|
|
33
|
+
pullRequest: {
|
|
34
|
+
number: pr.number,
|
|
35
|
+
title: pr.title,
|
|
36
|
+
state: pr.state,
|
|
37
|
+
draft: pr.draft,
|
|
38
|
+
merged: pr.merged,
|
|
39
|
+
url: pr.html_url,
|
|
40
|
+
author: {
|
|
41
|
+
login: pr.user.login,
|
|
42
|
+
url: `https://github.com/${pr.user.login}`,
|
|
43
|
+
},
|
|
44
|
+
createdAt: pr.created_at,
|
|
45
|
+
updatedAt: pr.updated_at,
|
|
46
|
+
mergedAt: pr.merged_at,
|
|
47
|
+
closedAt: pr.closed_at,
|
|
48
|
+
mergedBy: pr.merged_by
|
|
49
|
+
? {
|
|
50
|
+
login: pr.merged_by.login,
|
|
51
|
+
url: `https://github.com/${pr.merged_by.login}`,
|
|
52
|
+
}
|
|
53
|
+
: null,
|
|
54
|
+
base: {
|
|
55
|
+
ref: pr.base.ref,
|
|
56
|
+
sha: pr.base.sha,
|
|
57
|
+
},
|
|
58
|
+
head: {
|
|
59
|
+
ref: pr.head.ref,
|
|
60
|
+
sha: pr.head.sha,
|
|
61
|
+
},
|
|
62
|
+
additions: pr.additions,
|
|
63
|
+
deletions: pr.deletions,
|
|
64
|
+
changedFiles: pr.changed_files,
|
|
65
|
+
labels: pr.labels?.map((l) => ({ name: l.name, color: l.color })) || [],
|
|
66
|
+
assignees:
|
|
67
|
+
pr.assignees?.map((a) => ({
|
|
68
|
+
login: a.login,
|
|
69
|
+
url: `https://github.com/${a.login}`,
|
|
70
|
+
})) || [],
|
|
71
|
+
requestedReviewers:
|
|
72
|
+
pr.requested_reviewers?.map((r) => ({
|
|
73
|
+
login: r.login,
|
|
74
|
+
url: `https://github.com/${r.login}`,
|
|
75
|
+
})) || [],
|
|
76
|
+
milestone: pr.milestone
|
|
77
|
+
? { title: pr.milestone.title, number: pr.milestone.number }
|
|
78
|
+
: null,
|
|
79
|
+
body: pr.body,
|
|
80
|
+
},
|
|
81
|
+
commits: commits.map((c) => ({
|
|
82
|
+
sha: c.sha,
|
|
83
|
+
message: c.commit.message,
|
|
84
|
+
author: c.author?.login || c.commit.author?.name || 'unknown',
|
|
85
|
+
url: c.html_url,
|
|
86
|
+
date: c.commit.author?.date,
|
|
87
|
+
})),
|
|
88
|
+
files: files.map((f) => ({
|
|
89
|
+
filename: f.filename,
|
|
90
|
+
status: f.status,
|
|
91
|
+
additions: f.additions,
|
|
92
|
+
deletions: f.deletions,
|
|
93
|
+
previousFilename: f.previous_filename,
|
|
94
|
+
patch: f.patch,
|
|
95
|
+
})),
|
|
96
|
+
reviews: reviews.map((r) => ({
|
|
97
|
+
id: r.id,
|
|
98
|
+
author: r.user.login,
|
|
99
|
+
state: r.state,
|
|
100
|
+
body: r.body,
|
|
101
|
+
submittedAt: r.submitted_at,
|
|
102
|
+
})),
|
|
103
|
+
reviewComments: reviewComments.map((c) => ({
|
|
104
|
+
id: c.id,
|
|
105
|
+
author: c.user.login,
|
|
106
|
+
body: c.body,
|
|
107
|
+
path: c.path,
|
|
108
|
+
line: c.line,
|
|
109
|
+
createdAt: c.created_at,
|
|
110
|
+
diffHunk: c.diff_hunk,
|
|
111
|
+
reviewId: c.pull_request_review_id,
|
|
112
|
+
})),
|
|
113
|
+
comments: comments.map((c) => ({
|
|
114
|
+
id: c.id,
|
|
115
|
+
author: c.user.login,
|
|
116
|
+
body: c.body,
|
|
117
|
+
createdAt: c.created_at,
|
|
118
|
+
})),
|
|
119
|
+
downloadedImages: downloadedImages.map((img) => ({
|
|
120
|
+
originalUrl: img.originalUrl,
|
|
121
|
+
localPath: img.relativePath,
|
|
122
|
+
format: img.format,
|
|
123
|
+
})),
|
|
124
|
+
},
|
|
125
|
+
null,
|
|
126
|
+
2
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Generate markdown for metadata section
|
|
132
|
+
* @param {Object} pr - Pull request data
|
|
133
|
+
* @returns {string} Markdown content
|
|
134
|
+
*/
|
|
135
|
+
export function generateMetadataMarkdown(pr) {
|
|
136
|
+
let markdown = `## Metadata\n\n`;
|
|
137
|
+
|
|
138
|
+
markdown += `| Field | Value |\n`;
|
|
139
|
+
markdown += `|-------|-------|\n`;
|
|
140
|
+
markdown += `| **Number** | #${pr.number} |\n`;
|
|
141
|
+
markdown += `| **URL** | ${pr.html_url} |\n`;
|
|
142
|
+
markdown += `| **Author** | [@${pr.user.login}](https://github.com/${pr.user.login}) |\n`;
|
|
143
|
+
markdown += `| **State** | ${pr.state}${pr.merged ? ' (merged)' : pr.draft ? ' (draft)' : ''} |\n`;
|
|
144
|
+
markdown += `| **Created** | ${formatDate(pr.created_at)} |\n`;
|
|
145
|
+
markdown += `| **Updated** | ${formatDate(pr.updated_at)} |\n`;
|
|
146
|
+
|
|
147
|
+
if (pr.merged_at) {
|
|
148
|
+
markdown += `| **Merged** | ${formatDate(pr.merged_at)} |\n`;
|
|
149
|
+
if (pr.merged_by) {
|
|
150
|
+
markdown += `| **Merged by** | [@${pr.merged_by.login}](https://github.com/${pr.merged_by.login}) |\n`;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (pr.closed_at && !pr.merged_at) {
|
|
154
|
+
markdown += `| **Closed** | ${formatDate(pr.closed_at)} |\n`;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
markdown += `| **Base** | \`${pr.base.ref}\` |\n`;
|
|
158
|
+
markdown += `| **Head** | \`${pr.head.ref}\` |\n`;
|
|
159
|
+
markdown += `| **Additions** | +${pr.additions} |\n`;
|
|
160
|
+
markdown += `| **Deletions** | -${pr.deletions} |\n`;
|
|
161
|
+
markdown += `| **Changed Files** | ${pr.changed_files} |\n`;
|
|
162
|
+
markdown += '\n';
|
|
163
|
+
|
|
164
|
+
if (pr.labels && pr.labels.length > 0) {
|
|
165
|
+
markdown += `**Labels:** ${pr.labels.map((l) => `\`${l.name}\``).join(', ')}\n\n`;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (pr.assignees && pr.assignees.length > 0) {
|
|
169
|
+
markdown += `**Assignees:** ${pr.assignees.map((a) => `[@${a.login}](https://github.com/${a.login})`).join(', ')}\n\n`;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (pr.requested_reviewers && pr.requested_reviewers.length > 0) {
|
|
173
|
+
markdown += `**Requested Reviewers:** ${pr.requested_reviewers.map((r) => `[@${r.login}](https://github.com/${r.login})`).join(', ')}\n\n`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (pr.milestone) {
|
|
177
|
+
markdown += `**Milestone:** ${pr.milestone.title}\n\n`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return markdown;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Generate markdown for commits section
|
|
185
|
+
* @param {Array} commits - Array of commit data
|
|
186
|
+
* @returns {string} Markdown content
|
|
187
|
+
*/
|
|
188
|
+
export function generateCommitsMarkdown(commits) {
|
|
189
|
+
if (commits.length === 0) {
|
|
190
|
+
return '';
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
let markdown = `## Commits (${commits.length})\n\n`;
|
|
194
|
+
|
|
195
|
+
for (const commit of commits) {
|
|
196
|
+
const message = commit.commit.message.split('\n')[0];
|
|
197
|
+
const sha = commit.sha.substring(0, 7);
|
|
198
|
+
const author =
|
|
199
|
+
commit.author?.login || commit.commit.author?.name || 'unknown';
|
|
200
|
+
const authorLink = commit.author
|
|
201
|
+
? `[@${author}](https://github.com/${author})`
|
|
202
|
+
: author;
|
|
203
|
+
markdown += `- [\`${sha}\`](${commit.html_url}) ${message} — ${authorLink}\n`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
markdown += '\n';
|
|
207
|
+
return markdown;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Generate markdown for files changed section
|
|
212
|
+
* @param {Array} files - Array of file data
|
|
213
|
+
* @returns {string} Markdown content
|
|
214
|
+
*/
|
|
215
|
+
export function generateFilesMarkdown(files) {
|
|
216
|
+
if (files.length === 0) {
|
|
217
|
+
return '';
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
let markdown = `## Files Changed (${files.length})\n\n`;
|
|
221
|
+
markdown += `| Status | File | Changes |\n`;
|
|
222
|
+
markdown += `|--------|------|--------:|\n`;
|
|
223
|
+
|
|
224
|
+
for (const file of files) {
|
|
225
|
+
const statusIcon =
|
|
226
|
+
file.status === 'added'
|
|
227
|
+
? '🆕 Added'
|
|
228
|
+
: file.status === 'removed'
|
|
229
|
+
? '🗑️ Removed'
|
|
230
|
+
: file.status === 'modified'
|
|
231
|
+
? '✏️ Modified'
|
|
232
|
+
: file.status === 'renamed'
|
|
233
|
+
? '📝 Renamed'
|
|
234
|
+
: `📄 ${file.status}`;
|
|
235
|
+
const changes = `+${file.additions} -${file.deletions}`;
|
|
236
|
+
let filename = file.filename;
|
|
237
|
+
if (file.status === 'renamed' && file.previous_filename) {
|
|
238
|
+
filename = `${file.previous_filename} → ${file.filename}`;
|
|
239
|
+
}
|
|
240
|
+
markdown += `| ${statusIcon} | \`${filename}\` | ${changes} |\n`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
markdown += '\n';
|
|
244
|
+
return markdown;
|
|
245
|
+
}
|