issues = new ArrayList<>();
274 | issues.add(newIssue("Bug 1 for ``", "1", "bug-1-url", Type.BUG));
275 | given(this.service.getMilestoneNumber("v2.3", REPO)).willReturn(23);
276 | given(this.service.getIssuesForMilestone(23, REPO)).willReturn(issues);
277 | Path file = generateChangelog("v2.3");
278 | assertThat(new String(Files.readAllBytes(file))).contains("Bug 1 for ` | `");
279 | }
280 |
281 | @Test
282 | void generateWhenMarkdownStylingIsInIssueTitleItIsEscaped() throws IOException {
283 | setupGenerator(MilestoneReference.TITLE);
284 | List issues = new ArrayList<>();
285 | issues.add(newIssue("Bug 1 for *italic*", "1", "bug-1-url", Type.BUG));
286 | issues.add(newIssue("Bug 2 for _italic_", "2", "bug-2-url", Type.BUG));
287 | issues.add(newIssue("Bug 3 for **bold**", "3", "bug-3-url", Type.BUG));
288 | issues.add(newIssue("Bug 4 for __bold__", "4", "bug-4-url", Type.BUG));
289 | issues.add(newIssue("Bug 5 for ~strikethrough~", "4", "bug-4-url", Type.BUG));
290 | given(this.service.getMilestoneNumber("v2.3", REPO)).willReturn(23);
291 | given(this.service.getIssuesForMilestone(23, REPO)).willReturn(issues);
292 | Path file = generateChangelog("v2.3");
293 | assertThat(new String(Files.readAllBytes(file))).contains("Bug 1 for \\*italic\\*");
294 | assertThat(new String(Files.readAllBytes(file))).contains("Bug 2 for \\_italic\\_");
295 | assertThat(new String(Files.readAllBytes(file))).contains("Bug 3 for \\*\\*bold\\*\\*");
296 | assertThat(new String(Files.readAllBytes(file))).contains("Bug 4 for \\_\\_bold\\_\\_");
297 | assertThat(new String(Files.readAllBytes(file))).contains("Bug 5 for \\~strikethrough\\~");
298 | }
299 |
300 | @Test
301 | void generateWhenMarkdownStylingWithinBackTicksIsInIssueTitleItIsNotEscaped() throws IOException {
302 | setupGenerator(MilestoneReference.TITLE);
303 | List issues = new ArrayList<>();
304 | issues.add(newIssue("Clarify `FactoryBean.OBJECT_TYPE_ATTRIBUTE` supported types", "1", "bug-1-url", Type.BUG));
305 | given(this.service.getMilestoneNumber("v2.3", REPO)).willReturn(23);
306 | given(this.service.getIssuesForMilestone(23, REPO)).willReturn(issues);
307 | Path file = generateChangelog("v2.3");
308 | assertThat(new String(Files.readAllBytes(file)))
309 | .contains("Clarify `FactoryBean.OBJECT_TYPE_ATTRIBUTE` supported types");
310 | }
311 |
312 | @Test
313 | void generateWhenEscapedMarkdownStylingIsInIssueTitleItIsNotEscapedAgain() throws IOException {
314 | setupGenerator(MilestoneReference.TITLE);
315 | List issues = new ArrayList<>();
316 | issues.add(newIssue("Bug 1 for ``", "1", "bug-1-url", Type.BUG));
317 | given(this.service.getMilestoneNumber("v2.3", REPO)).willReturn(23);
318 | given(this.service.getIssuesForMilestone(23, REPO)).willReturn(issues);
319 | Path file = generateChangelog("v2.3");
320 | assertThat(new String(Files.readAllBytes(file))).contains("Bug 1 for ` | `");
321 | }
322 |
323 | @Test
324 | void generateWhenSectionSortedByTitle() throws Exception {
325 | List sections = new ArrayList<>();
326 | Set labels = Collections.singleton("type: enhancement");
327 | sections.add(new Section("Enhancements", null, IssueSort.TITLE, labels, IssueType.ANY));
328 | ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, sections,
329 | new Issues(null, null, null, true), null, null, false);
330 | this.generator = new ChangelogGenerator(this.service, properties);
331 | List issues = new ArrayList<>();
332 | issues.add(newIssue("Enhancement c", "1", "enhancement-1-url", Type.ENHANCEMENT));
333 | issues.add(newIssue("Enhancement z", "2", "enhancement-2-url", Type.ENHANCEMENT));
334 | issues.add(newIssue("enHAncEMent a", "3", "enhancement-3-url", Type.ENHANCEMENT));
335 | given(this.service.getIssuesForMilestone(23, REPO)).willReturn(issues);
336 | assertChangelog("23").hasContent(from("output-with-title-sorted-issues"));
337 | }
338 |
339 | @Test
340 | void generateWhenAllIssuesSortedByTitle() throws Exception {
341 | List sections = new ArrayList<>();
342 | Set labels = Collections.singleton("type: enhancement");
343 | sections.add(new Section("Enhancements", null, null, labels, IssueType.ANY));
344 | ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, sections,
345 | new Issues(IssueSort.TITLE, null, null, true), null, null, false);
346 | this.generator = new ChangelogGenerator(this.service, properties);
347 | List issues = new ArrayList<>();
348 | issues.add(newIssue("Enhancement c", "1", "enhancement-1-url", Type.ENHANCEMENT));
349 | issues.add(newIssue("Enhancement z", "2", "enhancement-2-url", Type.ENHANCEMENT));
350 | issues.add(newIssue("enHAncEMent a", "3", "enhancement-3-url", Type.ENHANCEMENT));
351 | given(this.service.getIssuesForMilestone(23, REPO)).willReturn(issues);
352 | assertChangelog("23").hasContent(from("output-with-title-sorted-issues"));
353 | }
354 |
355 | @Test
356 | void generateWhenHasCustomContributorsTitle() throws Exception {
357 | User contributor1 = createUser("contributor1");
358 | List issues = new ArrayList<>();
359 | issues.add(newPullRequest("Bug 1", "1", Type.BUG, "bug-1-url", contributor1));
360 | given(this.service.getIssuesForMilestone(23, REPO)).willReturn(issues);
361 | ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, null, null,
362 | new Contributors(":heart: Teamwork", null), null, false);
363 | this.generator = new ChangelogGenerator(this.service, properties);
364 | assertChangelog("23").hasContent(from("output-with-custom-contributors-title"));
365 | }
366 |
367 | @Test
368 | void generateWhenOneExternalLink() throws Exception {
369 | List externalLinks = new ArrayList<>();
370 | externalLinks.add(new ExternalLink("Release Notes Link 1", "url1"));
371 | ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, null, null, null,
372 | externalLinks, false);
373 | this.generator = new ChangelogGenerator(this.service, properties);
374 | assertChangelog("23").hasContent(from("output-with-one-external-link"));
375 | }
376 |
377 | @Test
378 | void generateWhenMultipleExternalLink() throws Exception {
379 | List externalLinks = new ArrayList<>();
380 | externalLinks.add(new ExternalLink("Release Notes Link 1", "url1"));
381 | externalLinks.add(new ExternalLink("Release Notes Link 2", "url2"));
382 | externalLinks.add(new ExternalLink("Release Notes Link 3", "url3"));
383 | ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, null, null, null,
384 | externalLinks, false);
385 | this.generator = new ChangelogGenerator(this.service, properties);
386 | assertChangelog("23").hasContent(from("output-with-multiple-external-link"));
387 | }
388 |
389 | @Test
390 | void generateWhenIssueLinksDisabled() throws Exception {
391 | User contributor1 = createUser("contributor1");
392 | List issues = new ArrayList<>();
393 | issues.add(newIssue("Bug 1", "1", "bug-1-url", Type.BUG));
394 | issues.add(newIssue("Bug 2", "2", "bug-2-url", Type.BUG, "wontfix"));
395 | issues.add(newPullRequest("PR 3", "3", Type.ENHANCEMENT, "pr-3-url", contributor1));
396 | issues.add(newPullRequest("PR 4", "4", Type.ENHANCEMENT, "pr-4-url", contributor1));
397 | given(this.service.getIssuesForMilestone(23, REPO)).willReturn(issues);
398 | ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, null,
399 | new Issues(null, null, null, false), null, null, false);
400 | this.generator = new ChangelogGenerator(this.service, properties);
401 | assertChangelog("23").hasContent(from("output-without-issue-links"));
402 | }
403 |
404 | @Test
405 | void generateWhenIssuesOnly() throws Exception {
406 | List sections = new ArrayList<>();
407 | Set labels = Collections.singleton("type: enhancement");
408 | sections.add(new Section("Enhancements", null, IssueSort.TITLE, labels, IssueType.ISSUE));
409 | ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, sections,
410 | new Issues(null, null, null, true), null, null, false);
411 | this.generator = new ChangelogGenerator(this.service, properties);
412 | User contributor1 = createUser("contributor1");
413 | List issues = new ArrayList<>();
414 | issues.add(newIssue("Issue 1", "1", "issue-1-url", Type.ENHANCEMENT));
415 | issues.add(newIssue("Issue 2", "2", "issue-2-url", Type.ENHANCEMENT));
416 | issues.add(newPullRequest("PR 3", "3", Type.ENHANCEMENT, "pr-3-url", contributor1));
417 | issues.add(newPullRequest("PR 4", "4", Type.ENHANCEMENT, "pr-4-url", contributor1));
418 | given(this.service.getIssuesForMilestone(23, REPO)).willReturn(issues);
419 | assertChangelog("23").hasContent(from("output-with-issues-only"));
420 | }
421 |
422 | @Test
423 | void generateWhenPullRequestsOnly() throws Exception {
424 | List sections = new ArrayList<>();
425 | Set labels = Collections.singleton("type: enhancement");
426 | sections.add(new Section("Enhancements", null, IssueSort.TITLE, labels, IssueType.PULL_REQUEST));
427 | ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, sections,
428 | new Issues(null, null, null, true), null, null, false);
429 | this.generator = new ChangelogGenerator(this.service, properties);
430 | User contributor1 = createUser("contributor1");
431 | List issues = new ArrayList<>();
432 | issues.add(newIssue("Issue 1", "1", "issue-1-url", Type.ENHANCEMENT));
433 | issues.add(newIssue("Issue 2", "2", "issue-2-url", Type.ENHANCEMENT));
434 | issues.add(newPullRequest("PR 3", "3", Type.ENHANCEMENT, "pr-3-url", contributor1));
435 | issues.add(newPullRequest("PR 4", "4", Type.ENHANCEMENT, "pr-4-url", contributor1));
436 | given(this.service.getIssuesForMilestone(23, REPO)).willReturn(issues);
437 | assertChangelog("23").hasContent(from("output-with-pull-requests-only"));
438 | }
439 |
440 | private void setupGenerator(MilestoneReference id) {
441 | Set labels = new HashSet<>(Arrays.asList("duplicate", "wontfix"));
442 | PortedIssue forwardPort = new PortedIssue("status: forward-port", "Forward port of issue #(\\d+)");
443 | PortedIssue cherryPick = new PortedIssue("status: back-port", "Back port of issue #(\\d+)");
444 | Set portedIssues = new HashSet<>(Arrays.asList(forwardPort, cherryPick));
445 | ApplicationProperties properties = new ApplicationProperties(REPO, id, null,
446 | new Issues(null, new IssuesExclude(labels), portedIssues, true), null, null, false);
447 | this.generator = new ChangelogGenerator(this.service, properties);
448 | }
449 |
450 | private PathAssert assertChangelog(String milestone) throws IOException {
451 | Path file = generateChangelog(milestone);
452 | return new PathAssert(file);
453 | }
454 |
455 | private Path generateChangelog(String milestone) throws IOException {
456 | Path file = this.tempDirectory.resolve(Path.of(UUID.randomUUID().toString(), "changelog.md"));
457 | this.generator.generate(milestone, file.normalize().toString());
458 | return file;
459 | }
460 |
461 | private User createUser(String id) {
462 | return new User(id);
463 | }
464 |
465 | private String from(String path) throws IOException {
466 | return FileCopyUtils.copyToString(new InputStreamReader(getClass().getResourceAsStream(path)));
467 | }
468 |
469 | private Issue newIssue(String title, String number, String url, Type type) {
470 | return new Issue(number, title, null, type.getLabels(), url, null, null);
471 | }
472 |
473 | private Issue newIssue(String title, String number, String url, Type type, String... extraLabels) {
474 | List | |