Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions src/main/java/ch/repnik/intellij/CommitPrefixCheckinHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.checkin.CheckinHandler;
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
import com.intellij.openapi.vcs.ui.CommitMessage;
import com.intellij.openapi.vcs.ui.RefreshableOnComponent;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.impl.PsiDocumentManagerImpl;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.UIUtil;
import git4idea.GitLocalBranch;
import git4idea.branch.GitBranchUtil;
import git4idea.repo.GitRepository;
Expand Down Expand Up @@ -53,7 +55,7 @@ private void updateCommitMessage() {
PsiDocumentManager psiInstance = PsiDocumentManager.getInstance(this.panel.getProject());
if (psiInstance instanceof PsiDocumentManagerImpl) {
if (!((PsiDocumentManagerImpl) psiInstance).isCommitInProgress()) {
panel.setCommitMessage(getNewCommitMessage());
getNewCommitMessage().ifPresent(this::setCommitMessageWithoutFocus);
} else {
log.info("PsiDocumentManager reported commit in progress. Skipping Git Auto Prefix");
}
Expand All @@ -63,6 +65,22 @@ private void updateCommitMessage() {
});
}

/**
* Sets the commit message without requesting focus.
* panel.setCommitMessage() would call CommitMessageUi.focus() (see CommitProjectPanelAdapter)
* which steals the focus e.g. from the terminal when switching branches.
*/
private void setCommitMessageWithoutFocus(String newMessage) {
CommitMessage commitMessageComponent =
UIUtil.findComponentOfType(panel.getComponent(), CommitMessage.class);
if (commitMessageComponent != null) {
commitMessageComponent.setCommitMessage(newMessage);
} else {
// Fallback for unknown CheckinProjectPanel implementations (may move focus)
panel.setCommitMessage(newMessage);
}
}

@Nullable
@Override
public RefreshableOnComponent getBeforeCheckinConfigurationPanel() {
Expand All @@ -71,18 +89,30 @@ public RefreshableOnComponent getBeforeCheckinConfigurationPanel() {
return super.getBeforeCheckinConfigurationPanel();
}

private String getNewCommitMessage() {
private Optional<String> getNewCommitMessage() {
String branchName = extractBranchName();
// log.warn("BranchName: " + branchName);

Optional<String> ticketName = getTicket(getTicketSystem(), branchName);
return calculateNewCommitMessage(getTicketSystem(), branchName, panel.getCommitMessage(),
getWrapLeft(), getWrapRight(), getIssueKeyPosition());
}

static Optional<String> calculateNewCommitMessage(TicketSystem ticketSystem, String branchName,
String currentMessage, String wrapLeft, String wrapRight, Position issueKeyPosition) {
Optional<String> ticketName = getTicket(ticketSystem, branchName);

if (ticketName.isPresent()) {
// Sets the value for the new Panel UI
return updatePrefix(ticketName.get(), panel.getCommitMessage(), getTicketSystem(), getWrapLeft(), getWrapRight(), getIssueKeyPosition());
if (!ticketName.isPresent()) {
return Optional.empty();
}

String newMessage = updatePrefix(ticketName.get(), currentMessage, ticketSystem, wrapLeft, wrapRight, issueKeyPosition);

// CommitMessage.getText() trims trailing whitespace, so compare rTrimmed to detect real changes
if (rTrim(newMessage).equals(currentMessage == null ? "" : rTrim(currentMessage))) {
return Optional.empty();
}

return panel.getCommitMessage();
return Optional.of(newMessage);
}

static Optional<String> getTicket(TicketSystem ticketSystem, String branchName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,45 @@ public void getTicketName_branchNameStartingWithDigit_returnsTicket(TicketNameTe
}


static Stream<Arguments> calculateNewCommitMessage_messageUnchanged_returnsEmpty() {
CalculateMessageTester startTemplate = new CalculateMessageTester().withWrapLeft("").withWrapRight(": ").withIssueKeyPosition(Position.START);
CalculateMessageTester endTemplate = new CalculateMessageTester().withWrapLeft(": ").withWrapRight("").withIssueKeyPosition(Position.END);

return Stream.of(
Arguments.of(startTemplate.withTicketSystem(JIRA).withBranchName("main").withCurrentMessage("Some message")),
Arguments.of(startTemplate.withTicketSystem(JIRA).withBranchName("develop").withCurrentMessage("")),
Arguments.of(startTemplate.withTicketSystem(JIRA).withBranchName("feature/ABC-1234-app-not-working").withCurrentMessage("ABC-1234: This is my text")),
Arguments.of(startTemplate.withTicketSystem(JIRA).withBranchName("feature/ABC-1234-app-not-working").withCurrentMessage("ABC-1234:")),
Arguments.of(endTemplate.withTicketSystem(JIRA).withBranchName("feature/ABC-1234-app-not-working").withCurrentMessage("This is my text: ABC-1234")),
Arguments.of(startTemplate.withTicketSystem(OTHER).withBranchName("feature/5678-app-not-working").withCurrentMessage("5678: This is my text"))
);
}

@ParameterizedTest
@MethodSource
public void calculateNewCommitMessage_messageUnchanged_returnsEmpty(CalculateMessageTester tester) {
tester.calculate().assertEmpty();
}

static Stream<Arguments> calculateNewCommitMessage_messageChanged_returnsNewMessage() {
CalculateMessageTester startTemplate = new CalculateMessageTester().withWrapLeft("").withWrapRight(": ").withIssueKeyPosition(Position.START);
CalculateMessageTester endTemplate = new CalculateMessageTester().withWrapLeft(": ").withWrapRight("").withIssueKeyPosition(Position.END);

return Stream.of(
Arguments.of(startTemplate.withTicketSystem(JIRA).withBranchName("feature/ABC-1234-app-not-working").withCurrentMessage(null), "ABC-1234: "),
Arguments.of(startTemplate.withTicketSystem(JIRA).withBranchName("feature/ABC-1234-app-not-working").withCurrentMessage("XYXY-837292: This is my text"), "ABC-1234: This is my text"),
Arguments.of(endTemplate.withTicketSystem(JIRA).withBranchName("feature/ABC-1234-app-not-working").withCurrentMessage("This is my text: XYXY-837292"), "This is my text: ABC-1234"),
Arguments.of(startTemplate.withTicketSystem(OTHER).withBranchName("feature/5678-app-not-working").withCurrentMessage("1111: This is my text"), "5678: This is my text")
);
}

@ParameterizedTest
@MethodSource
public void calculateNewCommitMessage_messageChanged_returnsNewMessage(CalculateMessageTester tester, String expectedMessage) {
tester.calculate().assertMessage(expectedMessage);
}



@With
@AllArgsConstructor
Expand Down Expand Up @@ -572,4 +611,45 @@ void doAssertion(String expectedTicketName) {
assertThat(actualTicketName.get(), is(expectedTicketName));
}
}


@With
@AllArgsConstructor
@NoArgsConstructor
static class CalculateMessageTester {

private TicketSystem ticketSystem;
private String branchName;
private String currentMessage;
private String wrapLeft;
private String wrapRight;
private Position issueKeyPosition;

CalculateMessageAsserter calculate() {
Optional<String> newMessage =
CommitPrefixCheckinHandler.calculateNewCommitMessage(
ticketSystem, branchName, currentMessage, wrapLeft, wrapRight, issueKeyPosition);
return new CalculateMessageAsserter(newMessage);
}

@Override
public String toString() {
return String.format("%s, %s, %s", ticketSystem.toString(), branchName, currentMessage);
}
}

@RequiredArgsConstructor
static class CalculateMessageAsserter {

private final Optional<String> actualMessage;

void assertEmpty() {
assertThat(actualMessage.isPresent(), is(false));
}

void assertMessage(String expectedMessage) {
assertThat(actualMessage.isPresent(), is(true));
assertThat(actualMessage.get(), is(expectedMessage));
}
}
}