From 4a149591a20f91daff3d67137d59d005badd682d Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Tue, 2 Aug 2016 15:11:18 +0300 Subject: [PATCH] IDEA-65721 Git Sign-off Add a checkbox to the commit dialog which calls `git commit -s` thus adding "Signed-off-by" suffix to the commit message. There was an idea to add a toggle button which wouldn't call "-s", but modify the commit message in place. However it appeared that this process could cause confusion in several cases, e.g.: * user usually signs commits in this project; * he opens the commit dialog, the signature is already there at the end of the previous commit message; * the commit message is selected to ease writing new commit message; * user starts typing, everything gets erased => * should the sign-off suffix be added or not? The button is still toggled, because it is a project wide control. The checkbox is a bit less neat option, but lets avoid such confusions. The state of the checkbox is remembered in Git project settings. Several methods became non-static to avoid passing 3-4 parameters which can be easily retrieved from the class fields. --- .../checkin/GitCheckinEnvironment.java | 70 +++++++++++-------- .../src/git4idea/config/GitVcsSettings.java | 10 +++ 2 files changed, 50 insertions(+), 30 deletions(-) diff --git a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java index 3aebc1bfdd73..d0a92ddeeb35 100644 --- a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java +++ b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java @@ -39,6 +39,7 @@ import com.intellij.openapi.vcs.ui.RefreshableOnComponent; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.EditorTextField; import com.intellij.ui.GuiUtils; +import com.intellij.ui.components.JBCheckBox; import com.intellij.ui.components.JBLabel; import com.intellij.util.FunctionUtil; import com.intellij.util.NullableFunction; @@ -73,6 +74,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; +import java.awt.event.KeyEvent; import java.io.*; import java.text.SimpleDateFormat; import java.util.*; @@ -99,6 +101,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { private boolean myNextCommitAmend; // If true, the next commit is amended private Boolean myNextCommitIsPushed = null; // The push option of the next commit private Date myNextCommitAuthorDate; + private boolean myNextCommitSignOff; public GitCheckinEnvironment(@NotNull Project project, @NotNull final VcsDirtyScopeManager dirtyScopeManager, @@ -225,7 +228,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { Set files = new HashSet<>(); files.addAll(added); files.addAll(removed); - commit(myProject, root, files, messageFile, myNextCommitAuthor, myNextCommitAmend, myNextCommitAuthorDate); + commit(myProject, root, files, messageFile); } catch (VcsException ex) { PartialOperation partialOperation = isMergeCommit(ex); @@ -259,13 +262,13 @@ public class GitCheckinEnvironment implements CheckinEnvironment { } @NotNull - private static List commitWithCaseOnlyRename(@NotNull Project project, - @NotNull VirtualFile root, - @NotNull Set caseOnlyRenames, - @NotNull Set added, - @NotNull Set removed, - @NotNull File messageFile, - @Nullable String author) { + private List commitWithCaseOnlyRename(@NotNull Project project, + @NotNull VirtualFile root, + @NotNull Set caseOnlyRenames, + @NotNull Set added, + @NotNull Set removed, + @NotNull File messageFile, + @Nullable String author) { String rootPath = root.getPath(); LOG.info("Committing case only rename: " + getLogString(rootPath, caseOnlyRenames) + " in " + getShortRepositoryName(project, root)); @@ -364,13 +367,13 @@ public class GitCheckinEnvironment implements CheckinEnvironment { * @param partialOperation * @return true if merge commit was successful */ - private static boolean mergeCommit(final Project project, - final VirtualFile root, - final Set added, - final Set removed, - final File messageFile, - final String author, - List exceptions, @NotNull final PartialOperation partialOperation) { + private boolean mergeCommit(final Project project, + final VirtualFile root, + final Set added, + final Set removed, + final File messageFile, + final String author, + List exceptions, @NotNull final PartialOperation partialOperation) { HashSet realAdded = new HashSet<>(); HashSet realRemoved = new HashSet<>(); // perform diff @@ -459,16 +462,19 @@ public class GitCheckinEnvironment implements CheckinEnvironment { return true; } - private static void commitWithoutPaths(@NotNull Project project, - @NotNull VirtualFile root, - @NotNull File messageFile, - @Nullable String author) throws VcsException { + private void commitWithoutPaths(@NotNull Project project, + @NotNull VirtualFile root, + @NotNull File messageFile, + @Nullable String author) throws VcsException { GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.COMMIT); handler.setStdoutSuppressed(false); handler.addParameters("-F", messageFile.getAbsolutePath()); if (author != null) { handler.addParameters("--author=" + author); } + if (myNextCommitSignOff) { + handler.addParameters("--signoff"); + } handler.endOptions(); handler.run(); } @@ -573,17 +579,15 @@ public class GitCheckinEnvironment implements CheckinEnvironment { return rc; } - private static void commit(Project project, - VirtualFile root, - Collection files, - File message, - final String nextCommitAuthor, - boolean nextCommitAmend, Date nextCommitAuthorDate) + private void commit(@NotNull Project project, @NotNull VirtualFile root, @NotNull Collection files, @NotNull File message) throws VcsException { - boolean amend = nextCommitAmend; + boolean amend = myNextCommitAmend; for (List paths : VcsFileUtil.chunkPaths(root, files)) { GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.COMMIT); handler.setStdoutSuppressed(false); + if (myNextCommitSignOff) { + handler.addParameters("--signoff"); + } if (amend) { handler.addParameters("--amend"); } @@ -591,11 +595,11 @@ public class GitCheckinEnvironment implements CheckinEnvironment { amend = true; } handler.addParameters("--only", "-F", message.getAbsolutePath()); - if (nextCommitAuthor != null) { - handler.addParameters("--author=" + nextCommitAuthor); + if (myNextCommitAuthor != null) { + handler.addParameters("--author=" + myNextCommitAuthor); } - if (nextCommitAuthorDate != null) { - handler.addParameters("--date", COMMIT_DATE_FORMAT.format(nextCommitAuthorDate)); + if (myNextCommitAuthorDate != null) { + handler.addParameters("--date", COMMIT_DATE_FORMAT.format(myNextCommitAuthorDate)); } handler.endOptions(); handler.addParameters(paths); @@ -695,6 +699,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { @NotNull private final EditorTextField myAuthorField; @Nullable private Date myAuthorDate; @NotNull private AmendComponent myAmendComponent; + @NotNull private final JCheckBox mySignOffCheckbox; GitCheckinOptions(@NotNull Project project, @NotNull CheckinProjectPanel panel) { myVcs = assertNotNull(GitVcs.getInstance(project)); @@ -705,6 +710,8 @@ public class GitCheckinEnvironment implements CheckinEnvironment { authorLabel.setLabelFor(myAuthorField); myAmendComponent = new MyAmendComponent(project, panel); + mySignOffCheckbox = new JBCheckBox("Sign-off commit", mySettings.shouldSignOffCommit()); + mySignOffCheckbox.setMnemonic(KeyEvent.VK_G); GridBag gb = new GridBag(). setDefaultAnchor(GridBagConstraints.WEST). @@ -712,6 +719,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { myPanel = new JPanel(new GridBagLayout()); myPanel.add(authorLabel, gb.nextLine().next()); myPanel.add(myAuthorField, gb.next().fillCellHorizontally().weightx(1)); + myPanel.add(mySignOffCheckbox, gb.nextLine().next().coverLine()); myPanel.add(myAmendComponent.getComponent(), gb.nextLine().next().coverLine()); } @@ -787,6 +795,8 @@ public class GitCheckinEnvironment implements CheckinEnvironment { } myNextCommitAmend = myAmendComponent.isAmend(); myNextCommitAuthorDate = myAuthorDate; + mySettings.setSignOffCommit(mySignOffCheckbox.isSelected()); + myNextCommitSignOff = mySignOffCheckbox.isSelected(); } @Override diff --git a/plugins/git4idea/src/git4idea/config/GitVcsSettings.java b/plugins/git4idea/src/git4idea/config/GitVcsSettings.java index 9ed82b19d589..c027cfc57ad4 100644 --- a/plugins/git4idea/src/git4idea/config/GitVcsSettings.java +++ b/plugins/git4idea/src/git4idea/config/GitVcsSettings.java @@ -78,6 +78,7 @@ public class GitVcsSettings implements PersistentStateComponent