main
js 147 lines 3.51 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * INSTALLATION:
8 * - `$ npm install octokit
9 * - Get a token from https://github.com/settings/tokens for use in the command below,
10 * set the token value as the GITHUB_AUTH_TOKEN environment variable
11 *
12 * USAGE:
13 * - $ GITHUB_AUTH_TOKEN="..." git filter-branch -f --msg-filter "node update-commit-message.js" 2364096862b72cf4d801ef2008c54252335a2df9..HEAD
14 */
15
16 const {Octokit, App} = require('octokit');
17 const fs = require('fs');
18
19 const OWNER = 'facebook';
20 const REPO = 'react-forget';
21 const octokit = new Octokit({auth: process.env.GITHUB_AUTH_TOKEN});
22
23 const fetchPullRequest = async pullNumber => {
24 const response = await octokit.request(
25 'GET /repos/{owner}/{repo}/pulls/{pull_number}',
26 {
27 owner: OWNER,
28 repo: REPO,
29 pull_number: pullNumber,
30 headers: {
31 'X-GitHub-Api-Version': '2022-11-28',
32 },
33 }
34 );
35 return {body: response.data.body, title: response.data.title};
36 };
37
38 function formatCommitMessage(str) {
39 let formattedStr = '';
40 let line = '';
41
42 const trim = str.replace(/(\r\n|\n|\r)/gm, ' ').trim();
43 if (!trim) {
44 return '';
45 }
46
47 // Split the string into words
48 const words = trim.split(' ');
49 // Iterate over each word
50 for (let i = 0; i < words.length; i++) {
51 // If adding the next word doesn't exceed the line length limit, add it to the line
52 if ((line + words[i]).length <= 80) {
53 line += words[i] + ' ';
54 } else {
55 // Otherwise, add the line to the formatted string and start a new line
56 formattedStr += line + '\n';
57 line = words[i] + ' ';
58 }
59 }
60 // Add the last line to the formatted string
61 formattedStr += line;
62 return formattedStr;
63 }
64
65 function filterMsg(response) {
66 const {body, title} = response;
67
68 const msgs = body.split('\n\n').flatMap(x => x.split('\r\n'));
69
70 const newMessage = [];
71
72 // Add title
73 msgs.unshift(title);
74
75 for (const msg of msgs) {
76 // remove "Stack from [ghstack] blurb"
77 if (msg.startsWith('Stack from ')) {
78 continue;
79 }
80
81 // remove "* #1234"
82 if (msg.startsWith('* #')) {
83 continue;
84 }
85
86 // remove "* __->__ #1234"
87 if (msg.startsWith('* __')) {
88 continue;
89 }
90
91 const formattedStr = formatCommitMessage(msg);
92 if (!formattedStr) {
93 continue;
94 }
95 newMessage.push(formattedStr);
96 }
97
98 const updatedMsg = newMessage.join('\n\n');
99 return updatedMsg;
100 }
101
102 function parsePullRequestNumber(text) {
103 if (!text) {
104 return null;
105 }
106 const ghstackUrlRegex =
107 /https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/pull\/(\d+)/;
108 const ghstackMatch = text.match(ghstackUrlRegex);
109 if (ghstackMatch) {
110 return ghstackMatch[1];
111 }
112 const firstLine = text.split('\n').filter(text => text.trim().length > 0)[0];
113 if (firstLine == null) {
114 return null;
115 }
116 const prNumberRegex = /\(#(\d{3,})\)\s*$/;
117 const prNumberMatch = firstLine.match(prNumberRegex);
118 if (prNumberMatch) {
119 return prNumberMatch[1];
120 }
121 return null;
122 }
123
124 async function main() {
125 const data = fs.readFileSync(0, 'utf-8');
126 const pr = parsePullRequestNumber(data);
127
128 if (pr) {
129 try {
130 const response = await fetchPullRequest(pr);
131 if (!response.body) {
132 console.log(data);
133 return;
134 }
135 const newMessage = filterMsg(response);
136 console.log(newMessage);
137 return;
138 } catch (e) {
139 console.log(data);
140 return;
141 }
142 }
143
144 console.log(data);
145 }
146
147 main();