1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | Object.defineProperty(exports, "__esModule", { value: true });
|
18 | const slack = require("@atomist/slack-messages/SlackMessages");
|
19 | const _ = require("lodash");
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | function truncateCommitMessage(message, repo) {
|
27 | const title = message.split("\n")[0];
|
28 | const escapedTitle = slack.escape(title);
|
29 | const linkedTitle = linkIssues(escapedTitle, repo);
|
30 | if (linkedTitle.length <= 50) {
|
31 | return linkedTitle;
|
32 | }
|
33 | const splitRegExp = /(&(?:[gl]t|amp);|<.*?\||>)/;
|
34 | const titleParts = linkedTitle.split(splitRegExp);
|
35 | let truncatedTitle = "";
|
36 | let addNext = 1;
|
37 | let i;
|
38 | for (i = 0; i < titleParts.length; i++) {
|
39 | let newTitle = truncatedTitle;
|
40 | if (i % 2 === 0) {
|
41 | newTitle += titleParts[i];
|
42 | }
|
43 | else if (/^&(?:[gl]t|amp);$/.test(titleParts[i])) {
|
44 | newTitle += "&";
|
45 | }
|
46 | else if (/^<.*\|$/.test(titleParts[i])) {
|
47 | addNext = 2;
|
48 | continue;
|
49 | }
|
50 | else if (titleParts[i] === ">") {
|
51 | addNext = 1;
|
52 | continue;
|
53 | }
|
54 | if (newTitle.length > 50) {
|
55 | const l = 50 - newTitle.length;
|
56 | titleParts[i] = titleParts[i].slice(0, l) + "...";
|
57 | break;
|
58 | }
|
59 | truncatedTitle = newTitle;
|
60 | }
|
61 | return titleParts.slice(0, i + addNext).join("");
|
62 | }
|
63 | exports.truncateCommitMessage = truncateCommitMessage;
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 | function repoSlug(repo) {
|
71 | return `${repo.owner}/${repo.name}`;
|
72 | }
|
73 | exports.repoSlug = repoSlug;
|
74 | function htmlUrl(repo) {
|
75 | if (repo.org && repo.org.provider && repo.org.provider.url) {
|
76 | let providerUrl = repo.org.provider.url;
|
77 | if (providerUrl.slice(-1) === "/") {
|
78 | providerUrl = providerUrl.slice(0, -1);
|
79 | }
|
80 | return providerUrl;
|
81 | }
|
82 | else {
|
83 | return "https://github.com";
|
84 | }
|
85 | }
|
86 | exports.htmlUrl = htmlUrl;
|
87 | exports.DefaultGitHubApiUrl = "https://api.github.com/";
|
88 | function apiUrl(repo) {
|
89 | if (repo.org && repo.org.provider && repo.org.provider.url) {
|
90 | let providerUrl = repo.org.provider.apiUrl;
|
91 | if (providerUrl.slice(-1) === "/") {
|
92 | providerUrl = providerUrl.slice(0, -1);
|
93 | }
|
94 | return providerUrl;
|
95 | }
|
96 | else {
|
97 | return exports.DefaultGitHubApiUrl;
|
98 | }
|
99 | }
|
100 | exports.apiUrl = apiUrl;
|
101 | function userUrl(repo, login) {
|
102 | return `${htmlUrl(repo)}/${login}`;
|
103 | }
|
104 | exports.userUrl = userUrl;
|
105 | function avatarUrl(repo, login) {
|
106 | if (repo.org != null && repo.org.provider != null && repo.org.provider.url != null) {
|
107 | return `${htmlUrl(repo)}/avatars/${login}`;
|
108 | }
|
109 | else {
|
110 | return `https://avatars.githubusercontent.com/${login}`;
|
111 | }
|
112 | }
|
113 | exports.avatarUrl = avatarUrl;
|
114 | function commitUrl(repo, commit) {
|
115 | return `${htmlUrl(repo)}/${repoSlug(repo)}/commit/${commit.sha}`;
|
116 | }
|
117 | exports.commitUrl = commitUrl;
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 | function urlToImageAttachment(url) {
|
126 | const imageRegExp = /[^\/]+\.(?:png|jpe?g|gif|bmp)$/i;
|
127 | const imageMatch = imageRegExp.exec(url);
|
128 | if (imageMatch) {
|
129 | const image = imageMatch[0];
|
130 | return {
|
131 | text: image,
|
132 | image_url: url,
|
133 | fallback: image,
|
134 | };
|
135 | }
|
136 | else {
|
137 | return null;
|
138 | }
|
139 | }
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 | function extractImageUrls(body) {
|
151 | const slackLinkRegExp = /<(https?:\/\/.*?)(?:\|.*?)?>/g;
|
152 |
|
153 | const urlRegExp = /\bhttps?:\/\/[^\s<>\[\]]+[^\s`!()\[\]{};:'".,<>?«»“”‘’]/gi;
|
154 | const attachments = [];
|
155 | const bodyParts = body.split(slackLinkRegExp);
|
156 | for (let i = 0; i < bodyParts.length; i++) {
|
157 | if (i % 2 === 0) {
|
158 | let match;
|
159 |
|
160 | while (match = urlRegExp.exec(bodyParts[i])) {
|
161 | const url = match[0];
|
162 | const attachment = urlToImageAttachment(url);
|
163 | if (attachment) {
|
164 | attachments.push(attachment);
|
165 | }
|
166 | }
|
167 | }
|
168 | else {
|
169 | const url = bodyParts[i];
|
170 | const attachment = urlToImageAttachment(url);
|
171 | if (attachment) {
|
172 | attachments.push(attachment);
|
173 | }
|
174 | }
|
175 | }
|
176 | const uniqueAttachments = [];
|
177 | attachments.forEach(a => {
|
178 | if (!uniqueAttachments.some(ua => ua.image_url === a.image_url)) {
|
179 | uniqueAttachments.push(a);
|
180 | }
|
181 | });
|
182 | return uniqueAttachments;
|
183 | }
|
184 | exports.extractImageUrls = extractImageUrls;
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 | function linkIssues(body, repo) {
|
193 | if (!body || body.length === 0) {
|
194 | return body;
|
195 | }
|
196 | const splitter = /(\[.+?\](?:\[.*?\]|\(.+?\)|:\s*http.*)|^```.*\n[\S\s]*?^```\s*\n|<.+?>)/m;
|
197 | const bodyParts = body.split(splitter);
|
198 | const baseUrl = htmlUrl(repo);
|
199 | for (let j = 0; j < bodyParts.length; j += 2) {
|
200 | let newPart = bodyParts[j];
|
201 | const allIssueMentions = getIssueMentions(newPart);
|
202 | allIssueMentions.forEach(i => {
|
203 | const iMatchPrefix = (i.indexOf("#") === 0) ? `^|\\W` : repoIssueMatchPrefix;
|
204 | const iRegExp = new RegExp(`(${iMatchPrefix})${i}(?!\\w)`, "g");
|
205 | const iSlug = (i.indexOf("#") === 0) ? `${repo.owner}/${repo.name}${i}` : i;
|
206 | const iUrlPath = iSlug.replace("#", "/issues/");
|
207 | const iLink = slack.url(`${baseUrl}/${iUrlPath}`, i);
|
208 | newPart = newPart.replace(iRegExp, `\$1${iLink}`);
|
209 | });
|
210 | bodyParts[j] = newPart;
|
211 | }
|
212 | return bodyParts.join("");
|
213 | }
|
214 | exports.linkIssues = linkIssues;
|
215 | const gitHubUserMatch = "[a-zA-Z\\d]+(?:-[a-zA-Z\\d]+)*";
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 | const repoIssueMatchPrefix = "^|[[\\s:({]";
|
230 |
|
231 | const issueMentionMatch = `(?:^|(?:${repoIssueMatchPrefix})(${gitHubUserMatch})\/(${gitHubUserMatch})|\\W)#([1-9]\\d*)(?!\\w)`;
|
232 | const issueMentionRegExp = new RegExp(issueMentionMatch, "g");
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 | function getIssueMentions(msg = "") {
|
241 | const allMentions = [];
|
242 | let matches;
|
243 |
|
244 | while (matches = issueMentionRegExp.exec(msg)) {
|
245 | const owner = matches[1];
|
246 | const repo = matches[2];
|
247 | const issue = matches[3];
|
248 | const slug = (owner && repo) ? `${owner}/${repo}` : "";
|
249 | allMentions.push(`${slug}#${issue}`);
|
250 | }
|
251 | return _.uniq(allMentions);
|
252 | }
|
253 | exports.getIssueMentions = getIssueMentions;
|
254 |
|
\ | No newline at end of file |