48 private final Logger log = Logger.getLogger("org.openjdk.skara.bots.notify");
49
50 enum Mode {
51 ALL,
52 PR,
53 PR_ONLY
54 }
55
56 MailingListUpdater(MailingList list, EmailAddress recipient, EmailAddress sender, EmailAddress author,
57 boolean includeBranch, Mode mode, Map<String, String> headers, Pattern allowedAuthorDomains) {
58 this.list = list;
59 this.recipient = recipient;
60 this.sender = sender;
61 this.author = author;
62 this.includeBranch = includeBranch;
63 this.mode = mode;
64 this.headers = headers;
65 this.allowedAuthorDomains = allowedAuthorDomains;
66 }
67
68 private String patchToText(Patch patch) {
69 if (patch.status().isAdded()) {
70 return "+ " + patch.target().path().orElseThrow();
71 } else if (patch.status().isDeleted()) {
72 return "- " + patch.source().path().orElseThrow();
73 } else if (patch.status().isModified()) {
74 return "! " + patch.target().path().orElseThrow();
75 } else {
76 return "= " + patch.target().path().orElseThrow();
77 }
78 }
79
80 private String commitToTextBrief(HostedRepository repository, Commit commit) {
81 var writer = new StringWriter();
82 var printer = new PrintWriter(writer);
83
84 printer.println("Changeset: " + commit.hash().abbreviate());
85 printer.println("Author: " + commit.author().name() + " <" + commit.author().email() + ">");
86 if (!commit.author().equals(commit.committer())) {
87 printer.println("Committer: " + commit.committer().name() + " <" + commit.committer().email() + ">");
88 }
89 printer.println("Date: " + commit.date().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss +0000")));
90 printer.println("URL: " + repository.webUrl(commit.hash()));
91
92 return writer.toString();
93 }
94
95 private String commitToText(HostedRepository repository, Commit commit) {
96 var writer = new StringWriter();
97 var printer = new PrintWriter(writer);
98
99 printer.print(commitToTextBrief(repository, commit));
100 printer.println();
101 printer.println(String.join("\n", commit.message()));
102 printer.println();
103
104 for (var diff : commit.parentDiffs()) {
105 for (var patch : diff.patches()) {
106 printer.println(patchToText(patch));
107 }
108 }
109
110 return writer.toString();
111 }
112
113 private String tagAnnotationToText(HostedRepository repository, Tag.Annotated annotation) {
114 var writer = new StringWriter();
115 var printer = new PrintWriter(writer);
116
117 printer.println("Tagged by: " + annotation.author().name() + " <" + annotation.author().email() + ">");
118 printer.println("Date: " + annotation.date().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss +0000")));
119 printer.println();
120 printer.print(String.join("\n", annotation.message()));
121
122 return writer.toString();
123 }
124
125 private EmailAddress filteredAuthor(EmailAddress commitAddress) {
126 if (author != null) {
127 return author;
128 }
129 var allowedAuthorMatcher = allowedAuthorDomains.matcher(commitAddress.domain());
130 if (!allowedAuthorMatcher.matches()) {
131 return sender;
132 } else {
184 if (candidates.size() != 1) {
185 log.warning("Commit " + commit.hash() + " matches " + candidates.size() + " pull requests - expected 1");
186 ret.add(commit);
187 continue;
188 }
189
190 var candidate = candidates.get(0);
191 var prLink = candidate.webUrl();
192 var prLinkPattern = Pattern.compile("^(?:PR: )?" + Pattern.quote(prLink.toString()), Pattern.MULTILINE);
193
194 var rfrCandidates = rfrs.stream()
195 .filter(email -> prLinkPattern.matcher(email.body()).find())
196 .collect(Collectors.toList());
197 if (rfrCandidates.size() != 1) {
198 log.warning("Pull request " + prLink + " found in " + rfrCandidates.size() + " RFR threads - expected 1");
199 ret.add(commit);
200 continue;
201 }
202 var rfr = rfrCandidates.get(0);
203
204 var body = commitToText(repository, commit);
205 var email = Email.reply(rfr, "Re: [Integrated] " + rfr.subject(), body)
206 .sender(sender)
207 .author(commitToAuthor(commit))
208 .recipient(recipient)
209 .headers(headers)
210 .build();
211 list.post(email);
212 }
213
214 return ret;
215 }
216
217 private void sendCombinedCommits(HostedRepository repository, List<Commit> commits, Branch branch) {
218 if (commits.size() == 0) {
219 return;
220 }
221
222 var writer = new StringWriter();
223 var printer = new PrintWriter(writer);
224
225 for (var commit : commits) {
226 printer.println(commitToText(repository, commit));
227 }
228
229 var subject = commitsToSubject(repository, commits, branch);
230 var lastCommit = commits.get(commits.size() - 1);
231 var commitAddress = filteredAuthor(EmailAddress.from(lastCommit.committer().name(), lastCommit.committer().email()));
232 var email = Email.create(subject, writer.toString())
233 .sender(sender)
234 .author(commitAddress)
235 .recipient(recipient)
236 .headers(headers)
237 .build();
238
239 list.post(email);
240 }
241
242 @Override
243 public void handleCommits(HostedRepository repository, List<Commit> commits, Branch branch) {
244 switch (mode) {
245 case PR_ONLY:
246 filterAndSendPrCommits(repository, commits);
249 commits = filterAndSendPrCommits(repository, commits);
250 // fall-through
251 case ALL:
252 sendCombinedCommits(repository, commits, branch);
253 break;
254 }
255 }
256
257 @Override
258 public void handleOpenJDKTagCommits(HostedRepository repository, List<Commit> commits, OpenJDKTag tag, Tag.Annotated annotation) {
259 if (mode == Mode.PR_ONLY) {
260 return;
261 }
262 var writer = new StringWriter();
263 var printer = new PrintWriter(writer);
264
265 var taggedCommit = commits.get(commits.size() - 1);
266 if (annotation != null) {
267 printer.println(tagAnnotationToText(repository, annotation));
268 }
269 printer.println(commitToTextBrief(repository, taggedCommit));
270
271 printer.println("The following commits are included in " + tag.tag());
272 printer.println("========================================================");
273 for (var commit : commits) {
274 printer.print(commit.hash().abbreviate());
275 if (commit.message().size() > 0) {
276 printer.print(": " + commit.message().get(0));
277 }
278 printer.println();
279 }
280
281 var subject = tagToSubject(repository, taggedCommit.hash(), tag.tag());
282 var email = Email.create(subject, writer.toString())
283 .sender(sender)
284 .recipient(recipient)
285 .headers(headers);
286
287 if (annotation != null) {
288 email.author(annotationToAuthor(annotation));
289 } else {
290 email.author(commitToAuthor(taggedCommit));
291 }
292
293 list.post(email.build());
294 }
295
296 @Override
297 public void handleTagCommit(HostedRepository repository, Commit commit, Tag tag, Tag.Annotated annotation) {
298 if (mode == Mode.PR_ONLY) {
299 return;
300 }
301 var writer = new StringWriter();
302 var printer = new PrintWriter(writer);
303
304 if (annotation != null) {
305 printer.println(tagAnnotationToText(repository, annotation));
306 }
307 printer.println(commitToTextBrief(repository, commit));
308
309 var subject = tagToSubject(repository, commit.hash(), tag);
310 var email = Email.create(subject, writer.toString())
311 .sender(sender)
312 .recipient(recipient)
313 .headers(headers);
314
315 if (annotation != null) {
316 email.author(annotationToAuthor(annotation));
317 } else {
318 email.author(commitToAuthor(commit));
319 }
320
321 list.post(email.build());
322 }
323
324 private String newBranchSubject(HostedRepository repository, List<Commit> commits, Branch parent, Branch branch) {
325 var subject = new StringBuilder();
326 subject.append(repository.repositoryType().shortName());
327 subject.append(": ");
|
48 private final Logger log = Logger.getLogger("org.openjdk.skara.bots.notify");
49
50 enum Mode {
51 ALL,
52 PR,
53 PR_ONLY
54 }
55
56 MailingListUpdater(MailingList list, EmailAddress recipient, EmailAddress sender, EmailAddress author,
57 boolean includeBranch, Mode mode, Map<String, String> headers, Pattern allowedAuthorDomains) {
58 this.list = list;
59 this.recipient = recipient;
60 this.sender = sender;
61 this.author = author;
62 this.includeBranch = includeBranch;
63 this.mode = mode;
64 this.headers = headers;
65 this.allowedAuthorDomains = allowedAuthorDomains;
66 }
67
68 private String tagAnnotationToText(HostedRepository repository, Tag.Annotated annotation) {
69 var writer = new StringWriter();
70 var printer = new PrintWriter(writer);
71
72 printer.println("Tagged by: " + annotation.author().name() + " <" + annotation.author().email() + ">");
73 printer.println("Date: " + annotation.date().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss +0000")));
74 printer.println();
75 printer.print(String.join("\n", annotation.message()));
76
77 return writer.toString();
78 }
79
80 private EmailAddress filteredAuthor(EmailAddress commitAddress) {
81 if (author != null) {
82 return author;
83 }
84 var allowedAuthorMatcher = allowedAuthorDomains.matcher(commitAddress.domain());
85 if (!allowedAuthorMatcher.matches()) {
86 return sender;
87 } else {
139 if (candidates.size() != 1) {
140 log.warning("Commit " + commit.hash() + " matches " + candidates.size() + " pull requests - expected 1");
141 ret.add(commit);
142 continue;
143 }
144
145 var candidate = candidates.get(0);
146 var prLink = candidate.webUrl();
147 var prLinkPattern = Pattern.compile("^(?:PR: )?" + Pattern.quote(prLink.toString()), Pattern.MULTILINE);
148
149 var rfrCandidates = rfrs.stream()
150 .filter(email -> prLinkPattern.matcher(email.body()).find())
151 .collect(Collectors.toList());
152 if (rfrCandidates.size() != 1) {
153 log.warning("Pull request " + prLink + " found in " + rfrCandidates.size() + " RFR threads - expected 1");
154 ret.add(commit);
155 continue;
156 }
157 var rfr = rfrCandidates.get(0);
158
159 var body = CommitFormatters.commitToText(repository, commit);
160 var email = Email.reply(rfr, "Re: [Integrated] " + rfr.subject(), body)
161 .sender(sender)
162 .author(commitToAuthor(commit))
163 .recipient(recipient)
164 .headers(headers)
165 .build();
166 list.post(email);
167 }
168
169 return ret;
170 }
171
172 private void sendCombinedCommits(HostedRepository repository, List<Commit> commits, Branch branch) {
173 if (commits.size() == 0) {
174 return;
175 }
176
177 var writer = new StringWriter();
178 var printer = new PrintWriter(writer);
179
180 for (var commit : commits) {
181 printer.println(CommitFormatters.commitToText(repository, commit));
182 }
183
184 var subject = commitsToSubject(repository, commits, branch);
185 var lastCommit = commits.get(commits.size() - 1);
186 var commitAddress = filteredAuthor(EmailAddress.from(lastCommit.committer().name(), lastCommit.committer().email()));
187 var email = Email.create(subject, writer.toString())
188 .sender(sender)
189 .author(commitAddress)
190 .recipient(recipient)
191 .headers(headers)
192 .build();
193
194 list.post(email);
195 }
196
197 @Override
198 public void handleCommits(HostedRepository repository, List<Commit> commits, Branch branch) {
199 switch (mode) {
200 case PR_ONLY:
201 filterAndSendPrCommits(repository, commits);
204 commits = filterAndSendPrCommits(repository, commits);
205 // fall-through
206 case ALL:
207 sendCombinedCommits(repository, commits, branch);
208 break;
209 }
210 }
211
212 @Override
213 public void handleOpenJDKTagCommits(HostedRepository repository, List<Commit> commits, OpenJDKTag tag, Tag.Annotated annotation) {
214 if (mode == Mode.PR_ONLY) {
215 return;
216 }
217 var writer = new StringWriter();
218 var printer = new PrintWriter(writer);
219
220 var taggedCommit = commits.get(commits.size() - 1);
221 if (annotation != null) {
222 printer.println(tagAnnotationToText(repository, annotation));
223 }
224 printer.println(CommitFormatters.commitToTextBrief(repository, taggedCommit));
225
226 printer.println("The following commits are included in " + tag.tag());
227 printer.println("========================================================");
228 for (var commit : commits) {
229 printer.print(commit.hash().abbreviate());
230 if (commit.message().size() > 0) {
231 printer.print(": " + commit.message().get(0));
232 }
233 printer.println();
234 }
235
236 var subject = tagToSubject(repository, taggedCommit.hash(), tag.tag());
237 var email = Email.create(subject, writer.toString())
238 .sender(sender)
239 .recipient(recipient)
240 .headers(headers);
241
242 if (annotation != null) {
243 email.author(annotationToAuthor(annotation));
244 } else {
245 email.author(commitToAuthor(taggedCommit));
246 }
247
248 list.post(email.build());
249 }
250
251 @Override
252 public void handleTagCommit(HostedRepository repository, Commit commit, Tag tag, Tag.Annotated annotation) {
253 if (mode == Mode.PR_ONLY) {
254 return;
255 }
256 var writer = new StringWriter();
257 var printer = new PrintWriter(writer);
258
259 if (annotation != null) {
260 printer.println(tagAnnotationToText(repository, annotation));
261 }
262 printer.println(CommitFormatters.commitToTextBrief(repository, commit));
263
264 var subject = tagToSubject(repository, commit.hash(), tag);
265 var email = Email.create(subject, writer.toString())
266 .sender(sender)
267 .recipient(recipient)
268 .headers(headers);
269
270 if (annotation != null) {
271 email.author(annotationToAuthor(annotation));
272 } else {
273 email.author(commitToAuthor(commit));
274 }
275
276 list.post(email.build());
277 }
278
279 private String newBranchSubject(HostedRepository repository, List<Commit> commits, Branch parent, Branch branch) {
280 var subject = new StringBuilder();
281 subject.append(repository.repositoryType().shortName());
282 subject.append(": ");
|