forked from mlflow/mlflow
-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathpreview-comment.js
More file actions
236 lines (199 loc) · 7.09 KB
/
Copy pathpreview-comment.js
File metadata and controls
236 lines (199 loc) · 7.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/**
* Script to manage documentation preview comments on pull requests.
*/
const path = require("path");
const MARKER = "<!-- documentation preview -->";
/**
* Fetch changed files from a pull request
* @param {object} params - Parameters object
* @param {object} params.github - GitHub API client
* @param {string} params.owner - Repository owner
* @param {string} params.repo - Repository name
* @param {string} params.pullNumber - Pull request number
* @returns {Promise<Array<{filename: string, status: string}>>} Array of changed file objects with filename and status
*/
async function fetchChangedFiles({ github, owner, repo, pullNumber }) {
const iterator = github.paginate.iterator(github.rest.pulls.listFiles, {
owner,
repo,
pull_number: pullNumber,
per_page: 100,
});
const changedFiles = [];
for await (const { data } of iterator) {
changedFiles.push(...data.map(({ filename, status }) => ({ filename, status })));
}
return changedFiles;
}
/**
* Get changed documentation pages from the list of changed files
* @param {Array<{filename: string, status: string}>} changedFiles - Array of changed file objects
* @returns {Array<{page: string, status: string}>} Array of documentation page objects with page path and status
*/
function getChangedDocPages(changedFiles) {
const DOCS_DIR = "docs/docs/";
const changedPages = [];
for (const { filename, status } of changedFiles) {
const ext = path.extname(filename);
if (ext !== ".md" && ext !== ".mdx") continue;
if (!filename.startsWith(DOCS_DIR)) continue;
const relativePath = path.relative(DOCS_DIR, filename);
const { dir, name, base } = path.parse(relativePath);
let pagePath;
if (base === "index.mdx") {
pagePath = dir;
} else {
pagePath = path.join(dir, name);
}
// Adjust classic-ml/ to ml/
pagePath = pagePath.replace(/^classic-ml/, "ml");
// Ensure forward slashes for web paths
pagePath = pagePath.split(path.sep).join("/");
changedPages.push({ page: pagePath, status });
}
return changedPages;
}
/**
* Create or update a PR comment with documentation preview information
* @param {object} params - Parameters object
* @param {object} params.github - GitHub API client
* @param {string} params.owner - Repository owner
* @param {string} params.repo - Repository name
* @param {string} params.pullNumber - Pull request number
* @param {string} params.commentBody - Comment body content
*/
async function upsertComment({ github, owner, repo, pullNumber, commentBody }) {
// Get existing comments on the PR
const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number: pullNumber,
per_page: 100,
});
// Find existing preview docs comment
const existingComment = comments.find((comment) => comment.body.includes(MARKER));
const commentBodyWithMarker = `${MARKER}\n\n${commentBody}`;
if (!existingComment) {
console.log("Creating comment");
await github.rest.issues.createComment({
owner,
repo,
issue_number: pullNumber,
body: commentBodyWithMarker,
});
} else {
console.log("Updating comment");
await github.rest.issues.updateComment({
owner,
repo,
comment_id: existingComment.id,
body: commentBodyWithMarker,
});
}
}
/**
* Generate the comment template for documentation preview
* @param {object} params - Parameters object
* @param {string} params.commitSha - Git commit SHA
* @param {string} params.workflowRunLink - Link to the workflow run
* @param {string} params.docsWorkflowRunUrl - Link to the docs workflow run
* @param {string} params.mainMessage - Main message content
* @param {Array<{link: string, status: string}>} params.changedPages - Array of changed documentation page objects with link and status
* @returns {string} Comment template
*/
function getCommentTemplate({
commitSha,
workflowRunLink,
docsWorkflowRunUrl,
mainMessage,
changedPages,
}) {
let changedPagesSection = "";
if (changedPages && changedPages.length > 0) {
const pageLinks = changedPages.map(({ link, status }) => `- ${link} (${status})`).join("\n");
// Only collapse if there are more than 5 changed pages
if (changedPages.length > 5) {
changedPagesSection = `
<details>
<summary>Changed Pages (${changedPages.length})</summary>
${pageLinks}
</details>
`;
} else {
changedPagesSection = `
**Changed Pages (${changedPages.length})**
${pageLinks}
`;
}
}
return `
Documentation preview for ${commitSha} ${mainMessage}
${changedPagesSection}
<details>
<summary>More info</summary>
- Ignore this comment if this PR does not change the documentation.
- The preview is updated when a new commit is pushed to this PR.
- This comment was created by [this workflow run](${workflowRunLink}).
- The documentation was built by [this workflow run](${docsWorkflowRunUrl}).
</details>
`;
}
/**
* Main function to handle documentation preview comments
* @param {object} params - Parameters object containing context and github
* @param {object} params.github - GitHub API client
* @param {object} params.context - GitHub context
* @param {object} params.env - Environment variables
*/
module.exports = async ({ github, context, env }) => {
const commitSha = env.COMMIT_SHA;
const pullNumber = env.PULL_NUMBER;
const workflowRunId = env.WORKFLOW_RUN_ID;
const stage = env.STAGE;
const netlifyUrl = env.NETLIFY_URL;
const docsWorkflowRunUrl = env.DOCS_WORKFLOW_RUN_URL;
// Validate required parameters
if (!commitSha || !pullNumber || !workflowRunId || !stage || !docsWorkflowRunUrl) {
throw new Error(
"Missing required parameters: commit-sha, pull-number, workflow-run-id, stage, docs-workflow-run-url"
);
}
if (!["completed", "failed"].includes(stage)) {
throw new Error("Stage must be either 'completed' or 'failed'");
}
if (stage === "completed" && !netlifyUrl) {
throw new Error("netlify-url is required for completed stage");
}
const { owner, repo } = context.repo;
const workflowRunLink = `https://github.com/${owner}/${repo}/actions/runs/${workflowRunId}`;
let mainMessage;
let changedPages = [];
if (stage === "completed") {
mainMessage = `is available at:\n\n- ${netlifyUrl}`;
// Fetch changed files and get documentation pages
try {
const changedFiles = await fetchChangedFiles({ github, owner, repo, pullNumber });
const docPages = getChangedDocPages(changedFiles);
// Convert to clickable links with status if we have changed pages
if (docPages.length > 0) {
changedPages = docPages.map(({ page, status }) => ({
link: `[${page}](${netlifyUrl}/${page})`,
status,
}));
}
} catch (error) {
console.error("Error fetching changed files:", error);
// Continue without changed pages list
}
} else if (stage === "failed") {
mainMessage = "failed to build or deploy.";
}
const commentBody = getCommentTemplate({
commitSha,
workflowRunLink,
docsWorkflowRunUrl,
mainMessage,
changedPages,
});
await upsertComment({ github, owner, repo, pullNumber, commentBody });
};