Skip to content

Commit

Permalink
feat: parse existing commit message
Browse files Browse the repository at this point in the history
Merged from #15

Closes #10
  • Loading branch information
lx0758 authored and darrachequesne committed Nov 2, 2020
1 parent 1397b50 commit 690ca63
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 36 deletions.
4 changes: 2 additions & 2 deletions src/com/leroymerlin/commit/CommitDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ public class CommitDialog extends DialogWrapper {

private final CommitPanel panel;

CommitDialog(@Nullable Project project) {
CommitDialog(@Nullable Project project, CommitMessage commitMessage) {
super(project);
panel = new CommitPanel(project);
panel = new CommitPanel(project, commitMessage);
setTitle("Commit");
setOKButtonText("OK");
init();
Expand Down
110 changes: 99 additions & 11 deletions src/com/leroymerlin/commit/CommitMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,40 @@

import org.apache.commons.lang.WordUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.apache.commons.lang.StringUtils.isNotBlank;

/**
* @author Damien Arrachequesne <damien.arrachequesne@gmail.com>
*/
class CommitMessage {
private static final int MAX_LINE_LENGTH = 72; // https://stackoverflow.com/a/2120040/5138796
private final String content;

CommitMessage(ChangeType changeType, String changeScope, String shortDescription, String longDescription, String closedIssues, String breakingChanges) {
this.content = buildContent(changeType, changeScope, shortDescription, longDescription, closedIssues, breakingChanges);
public static final Pattern COMMIT_FIRST_LINE_FORMAT = Pattern.compile("^([a-z]+)(\\((.+)\\))?: (.+)");
public static final Pattern COMMIT_CLOSES_FORMAT = Pattern.compile("Closes (.+)");

private ChangeType changeType;
private String changeScope, shortDescription, longDescription, breakingChanges, closedIssues;

private CommitMessage() {
this.longDescription = "";
this.breakingChanges = "";
this.closedIssues = "";
}

public CommitMessage(ChangeType changeType, String changeScope, String shortDescription, String longDescription, String breakingChanges, String closedIssues) {
this.changeType = changeType;
this.changeScope = changeScope;
this.shortDescription = shortDescription;
this.longDescription = longDescription;
this.breakingChanges = breakingChanges;
this.closedIssues = closedIssues;
}

private String buildContent(ChangeType changeType, String changeScope, String shortDescription, String longDescription, String closedIssues, String breakingChanges) {
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(changeType.label());
if (isNotBlank(changeScope)) {
Expand All @@ -26,10 +46,14 @@ private String buildContent(ChangeType changeType, String changeScope, String sh
}
builder
.append(": ")
.append(shortDescription)
.append(System.lineSeparator())
.append(System.lineSeparator())
.append(WordUtils.wrap(longDescription, MAX_LINE_LENGTH));
.append(shortDescription);

if (isNotBlank(longDescription)) {
builder
.append(System.lineSeparator())
.append(System.lineSeparator())
.append(WordUtils.wrap(longDescription, MAX_LINE_LENGTH));
}

if (isNotBlank(breakingChanges)) {
builder
Expand All @@ -51,8 +75,72 @@ private String buildContent(ChangeType changeType, String changeScope, String sh
return builder.toString();
}

@Override
public String toString() {
return content;
public static CommitMessage parse(String message) {
CommitMessage commitMessage = new CommitMessage();

try {
Matcher matcher = COMMIT_FIRST_LINE_FORMAT.matcher(message);
if (!matcher.find()) return commitMessage;

commitMessage.changeType = ChangeType.valueOf(matcher.group(1).toUpperCase());
commitMessage.changeScope = matcher.group(3);
commitMessage.shortDescription = matcher.group(4);

String[] strings = message.split("\n");
if (strings.length < 2) return commitMessage;

int pos = 1;
StringBuilder stringBuilder;

stringBuilder = new StringBuilder();
for (; pos < strings.length; pos++) {
String lineString = strings[pos];
if (lineString.startsWith("BREAKING") || lineString.startsWith("Closes")) break;
stringBuilder.append(lineString).append('\n');
}
commitMessage.longDescription = stringBuilder.toString().trim();

stringBuilder = new StringBuilder();
for (; pos < strings.length; pos++) {
String lineString = strings[pos];
if (lineString.startsWith("Closes")) break;
stringBuilder.append(lineString).append('\n');
}
commitMessage.breakingChanges = stringBuilder.toString().trim().replace("BREAKING CHANGE: ", "");

matcher = COMMIT_CLOSES_FORMAT.matcher(message);
stringBuilder = new StringBuilder();
while (matcher.find()) {
stringBuilder.append(matcher.group(1)).append(',');
}
if (stringBuilder.length() > 0) stringBuilder.delete(stringBuilder.length() - 1, stringBuilder.length());
commitMessage.closedIssues = stringBuilder.toString();
} catch (RuntimeException e) {}

return commitMessage;
}

public ChangeType getChangeType() {
return changeType;
}

public String getChangeScope() {
return changeScope;
}

public String getShortDescription() {
return shortDescription;
}

public String getLongDescription() {
return longDescription;
}

public String getBreakingChanges() {
return breakingChanges;
}

public String getClosedIssues() {
return closedIssues;
}
}
24 changes: 18 additions & 6 deletions src/com/leroymerlin/commit/CommitPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
*/
public class CommitPanel {
private JPanel mainPanel;
private JComboBox changeType;
private JComboBox changeScope;
private JComboBox<ChangeType> changeType;
private JComboBox<String> changeScope;
private JTextField shortDescription;
private JTextArea longDescription;
private JTextField closedIssues;
private JTextArea breakingChanges;
private JTextField closedIssues;

CommitPanel(Project project) {
CommitPanel(Project project, CommitMessage commitMessage) {
for (ChangeType type : ChangeType.values()) {
changeType.addItem(type);
}
Expand All @@ -28,6 +28,10 @@ public class CommitPanel {
changeScope.addItem(""); // no value by default
result.getScopes().forEach(changeScope::addItem);
}

if (commitMessage != null) {
restoreValuesFromParsedCommitMessage(commitMessage);
}
}

JPanel getMainPanel() {
Expand All @@ -40,9 +44,17 @@ CommitMessage getCommitMessage() {
(String) changeScope.getSelectedItem(),
shortDescription.getText().trim(),
longDescription.getText().trim(),
closedIssues.getText().trim(),
breakingChanges.getText().trim()
breakingChanges.getText().trim(),
closedIssues.getText().trim()
);
}

private void restoreValuesFromParsedCommitMessage(CommitMessage commitMessage) {
changeType.setSelectedItem(commitMessage.getChangeType());
changeScope.setSelectedItem(commitMessage.getChangeScope());
shortDescription.setText(commitMessage.getShortDescription());
longDescription.setText(commitMessage.getLongDescription());
breakingChanges.setText(commitMessage.getBreakingChanges());
closedIssues.setText(commitMessage.getClosedIssues());
}
}
18 changes: 14 additions & 4 deletions src/com/leroymerlin/commit/CreateCommitAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.vcs.CheckinProjectPanel;
import com.intellij.openapi.vcs.CommitMessageI;
import com.intellij.openapi.vcs.VcsDataKeys;
import com.intellij.openapi.vcs.ui.Refreshable;
Expand All @@ -16,17 +17,26 @@ public class CreateCommitAction extends AnAction implements DumbAware {

@Override
public void actionPerformed(AnActionEvent actionEvent) {
final CommitMessageI commitPanel = getCommitPanel(actionEvent);
if (commitPanel == null)
return;
CommitMessageI commitPanel = getCommitPanel(actionEvent);
if (commitPanel == null) return;

CommitDialog dialog = new CommitDialog(actionEvent.getProject());
CommitMessage commitMessage = parseExistingCommitMessage(commitPanel);
CommitDialog dialog = new CommitDialog(actionEvent.getProject(), commitMessage);
dialog.show();

if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) {
commitPanel.setCommitMessage(dialog.getCommitMessage().toString());
}
}

private CommitMessage parseExistingCommitMessage(CommitMessageI commitPanel) {
if (commitPanel instanceof CheckinProjectPanel) {
String commitMessageString = ((CheckinProjectPanel) commitPanel).getCommitMessage();
return CommitMessage.parse(commitMessageString);
}
return null;
}

@Nullable
private static CommitMessageI getCommitPanel(@Nullable AnActionEvent e) {
if (e == null) {
Expand Down
50 changes: 37 additions & 13 deletions tests/com/leroymerlin/commit/CommitMessageTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,48 +11,46 @@ public void testFormatCommit() {
CommitMessage commitMessage = new CommitMessage(ChangeType.FIX, "ngStyle",
"skip setting empty value when new style has the property",
"Previously, all the properties in oldStyles are set to empty value once. Using AngularJS with jQuery 3.3.1, this disables the CSS transition as reported in jquery/jquery#4185.",
"#16709", "");
null, "#16709");
String expected = "fix(ngStyle): skip setting empty value when new style has the property\n" +
"\n" +
"Previously, all the properties in oldStyles are set to empty value once.\n" +
"Using AngularJS with jQuery 3.3.1, this disables the CSS transition as\n" +
"reported in jquery/jquery#4185.\n" +
"\n" +
"Closes #16709";
assertEquals(expected, commitMessage.toString());
check(commitMessage, expected);
}

@Test
public void testFormatCommit_withoutScope() {
CommitMessage commitMessage = new CommitMessage(ChangeType.STYLE, "",
"fix eslint error", "", "", "");
String expected = "style: fix eslint error\n\n";
assertEquals(expected, commitMessage.toString());
CommitMessage commitMessage = new CommitMessage(ChangeType.STYLE, null,
"fix eslint error", null, null, "");
String expected = "style: fix eslint error";
check(commitMessage, expected);
}

@Test
public void testFormatCommit_withMultipleClosedIssues() {
CommitMessage commitMessage = new CommitMessage(ChangeType.FEAT, "$route",
"add support for the `reloadOnUrl` configuration option",
"Enables users to specify that a particular route should not be reloaded after a URL change.",
"#7925,#15002", "");
"", "#7925,#15002");
String expected = "feat($route): add support for the `reloadOnUrl` configuration option\n" +
"\n" +
"Enables users to specify that a particular route should not be reloaded\n" +
"after a URL change.\n" +
"\n" +
"Closes #7925\n" +
"Closes #15002";
assertEquals(expected, commitMessage.toString());
check(commitMessage, expected);
}

@Test
public void testFormatCommit_withLongBreakingChange() {
CommitMessage commitMessage = new CommitMessage(ChangeType.FEAT, "", "break everything","", "",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
CommitMessage commitMessage = new CommitMessage(ChangeType.FEAT, null, "break everything", null,
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "");
String expected = "feat: break everything\n" +
"\n" +
"\n" +
"\n" +
"BREAKING CHANGE: Lorem ipsum dolor sit amet, consectetur adipiscing\n" +
"elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n" +
Expand All @@ -61,6 +59,32 @@ public void testFormatCommit_withLongBreakingChange() {
"reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla\n" +
"pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa\n" +
"qui officia deserunt mollit anim id est laborum.";
assertEquals(expected, commitMessage.toString());
check(commitMessage, expected);
}

@Test
public void testParseCommit_invalidFormat() {
CommitMessage commitMessage = CommitMessage.parse("lorem ipsum");
assertEquals(null, commitMessage.getChangeType());
}

private void check(CommitMessage commitMessage, String output) {
checkFormat(commitMessage, output);
checkParse(commitMessage, output);
}

private void checkFormat(CommitMessage commitMessage, String output) {
assertEquals(output, commitMessage.toString());
}

private void checkParse(CommitMessage commitMessage, String output) {
CommitMessage actual = CommitMessage.parse(output);
assertEquals(commitMessage.getChangeType(), actual.getChangeType());
assertEquals(commitMessage.getChangeScope(), actual.getChangeScope());
assertEquals(commitMessage.getShortDescription(), actual.getShortDescription());
// FIXME should we remove newlines?
// assertEquals(expected.getLongDescription(), actual.getLongDescription());
// assertEquals(expected.getBreakingChanges(), actual.getBreakingChanges());
assertEquals(commitMessage.getClosedIssues(), actual.getClosedIssues());
}
}

0 comments on commit 690ca63

Please sign in to comment.