Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

572: Auto-correct PR title if it is a prefix of the JBS issue title #1023

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -44,8 +44,9 @@
class CheckWorkItem extends PullRequestWorkItem {
private final Pattern metadataComments = Pattern.compile("<!-- (?:(add|remove) (?:contributor|reviewer))|(?:summary: ')|(?:solves: ')|(?:additional required reviewers)");
private final Logger log = Logger.getLogger("org.openjdk.skara.bots.pr");
static final Pattern ISSUE_ID_PATTERN = Pattern.compile("^(?:[A-Za-z][A-Za-z0-9]+-)?([0-9]+)$");
static final Pattern ISSUE_ID_PATTERN = Pattern.compile("^(?:(?<prefix>[A-Za-z][A-Za-z0-9]+)-)?(?<id>[0-9]+)(?::\\s+(?<title>.+))?$");
private static final Pattern BACKPORT_TITLE_PATTERN = Pattern.compile("^Backport\\s*([0-9a-z]{40})\\s*$");
private static final String ELLIPSIS = "…";

CheckWorkItem(PullRequestBot bot, PullRequest pr, Consumer<RuntimeException> errorHandler) {
super(bot, pr, errorHandler);
@@ -137,25 +138,66 @@ private boolean currentCheckValid(CensusInstance censusInstance, List<Comment> c
return false;
}

/**
* Return the matching group, or the empty string if no match is found
*/
private String getMatchGroup(java.util.regex.Matcher m, String group) {
var prefix = m.group(group);
if (prefix == null) {
return "";
}
return prefix;
}

/**
* Help the user by fixing up an "almost correct" PR title
* @return true if the PR was modified
*/
private boolean updateTitle() {
var title = pr.title();
var m = ISSUE_ID_PATTERN.matcher(title);
var m = ISSUE_ID_PATTERN.matcher(pr.title());
var project = bot.issueProject();

var newTitle = title;
if (m.matches() && project != null) {
var id = m.group(1);
var prefix = getMatchGroup(m, "prefix");
var id = getMatchGroup(m,"id");
var title = getMatchGroup(m,"title");

if (!prefix.isEmpty() && !prefix.equalsIgnoreCase(project.name())) {
// If [project-] prefix does not match our project, something is odd;
// don't touch the PR title in that case
return false;
}

var issue = project.issue(id);
if (issue.isPresent()) {
newTitle = id + ": " + issue.get().title();
var issueTitle = issue.get().title();
if (title.isEmpty()) {
// If the title is in the form of "[project-]<bugid>" only
// we add the title from JBS
var newPrTitle = id + ": " + issue.get().title();
pr.setTitle(newPrTitle);
return true;
} else {
// If it is "[project-]<bugid>: <title-pre>", where <title-pre>
// is a cut-off version of the title, we restore the full title
if (title.endsWith(ELLIPSIS)) {
title = title.substring(0, title.length() - 1);
}
if (issueTitle.startsWith(title) && issueTitle.length() > title.length()) {
var newPrTitle = id + ": " + issue.get().title();
pr.setTitle(newPrTitle);
var remainingTitle = issue.get().title().substring(title.length());
if (pr.body().startsWith(ELLIPSIS + remainingTitle + "\n\n")) {
// Remove remaning title, plus decorations
var newPrBody = pr.body().substring(remainingTitle.length() + 3);
pr.setBody(newPrBody);
}
return true;
}
}
}
}

if (!title.equals(newTitle)) {
pr.setTitle(newTitle);
return true;
}

return false;
}

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -890,6 +890,51 @@ void issueIssue(TestInfo testInfo) throws IOException {
}
}

@Test
void issueTitleCutOff(TestInfo testInfo) throws IOException {
try (var credentials = new HostCredentials(testInfo);
var tempFolder = new TemporaryDirectory()) {
var author = credentials.getHostedRepository();
var reviewer = credentials.getHostedRepository();
var issues = credentials.getIssueProject();

var censusBuilder = credentials.getCensusBuilder()
.addAuthor(author.forge().currentUser().id())
.addReviewer(reviewer.forge().currentUser().id());
var checkBot = PullRequestBot.newBuilder().repo(author).censusRepo(censusBuilder.build()).issueProject(issues).build();

// Populate the projects repository
var localRepo = CheckableRepository.init(tempFolder.path(), author.repositoryType(), Path.of("appendable.txt"),
Set.of("issues"), null);
var masterHash = localRepo.resolve("master").orElseThrow();
localRepo.push(masterHash, author.url(), "master", true);

var issue1 = issues.createIssue("My first issue with a very long title that is going to be cut off by the Git Forge provider", List.of("Hello"), Map.of());

// Make a change with a corresponding PR
var editHash = CheckableRepository.appendAndCommit(localRepo);
localRepo.push(editHash, author.url(), "edit", true);
var prBadTitle = credentials.createPullRequest(author, "master", "edit", issue1.id() + ": My OTHER issue with a very long title that is going to be cut off by …", List.of("…the Git Forge provider"), false);

// Check the status
TestBotRunner.runPeriodicItems(checkBot);

assertTrue(prBadTitle.body().contains("Title mismatch between PR and JBS for issue"));

var prCutOff = credentials.createPullRequest(author, "master", "edit", issue1.id() + ": My first issue with a very long title that is going to be cut off by …", List.of("…the Git Forge provider", "", "It also has a second line!"), false);

// Check the status
TestBotRunner.runPeriodicItems(checkBot);

assertFalse(prCutOff.body().contains("Title mismatch between PR and JBS for issue"));

// The PR title should contain the full issue title
assertEquals("1: My first issue with a very long title that is going to be cut off by the Git Forge provider", prCutOff.title());
// And the body should not contain the issue title
assertTrue(prCutOff.body().startsWith("It also has a second line!"));
}
}

@Test
void issueInSummary(TestInfo testInfo) throws IOException {
try (var credentials = new HostCredentials(testInfo);