mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-64049 Git: before commit check if user.name and user.email have been set, otherwise notify
Check if user.name/user.email is defined for all roots affected by commit. If not, display a dialog where user can defined the properties right away (globally or just for these roots).
This commit is contained in:
@@ -15,26 +15,37 @@
|
||||
*/
|
||||
package git4idea.checkin;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.CheckinProjectPanel;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.CommitExecutor;
|
||||
import com.intellij.openapi.vcs.checkin.CheckinHandler;
|
||||
import com.intellij.openapi.vcs.checkin.VcsCheckinHandlerFactory;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.PairConsumer;
|
||||
import git4idea.GitVcs;
|
||||
import git4idea.config.GitConfigUtil;
|
||||
import git4idea.i18n.GitBundle;
|
||||
import git4idea.repo.GitRepository;
|
||||
import git4idea.repo.GitRepositoryManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Prohibits commiting with an empty messages.
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
public class GitCheckinHandlerFactory extends VcsCheckinHandlerFactory {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(GitCheckinHandlerFactory.class);
|
||||
|
||||
public GitCheckinHandlerFactory() {
|
||||
super(GitVcs.getKey());
|
||||
}
|
||||
@@ -57,12 +68,99 @@ public class GitCheckinHandlerFactory extends VcsCheckinHandlerFactory {
|
||||
if (emptyCommitMessage()) {
|
||||
return ReturnResult.CANCEL;
|
||||
}
|
||||
|
||||
ReturnResult result = checkUserName();
|
||||
if (result != ReturnResult.COMMIT) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (commitOrCommitAndPush(executor)) {
|
||||
return warnAboutDetachedHeadIfNeeded();
|
||||
}
|
||||
return ReturnResult.COMMIT;
|
||||
}
|
||||
|
||||
private ReturnResult checkUserName() {
|
||||
Project project = myPanel.getProject();
|
||||
Collection<VirtualFile> notDefined = new ArrayList<VirtualFile>();
|
||||
Map<VirtualFile, Pair<String, String>> defined = new HashMap<VirtualFile, Pair<String, String>>();
|
||||
Collection<VirtualFile> allRoots = new ArrayList<VirtualFile>(Arrays.asList(
|
||||
ProjectLevelVcsManager.getInstance(project).getRootsUnderVcs(GitVcs.getInstance(project))));
|
||||
|
||||
Collection<VirtualFile> affectedRoots = myPanel.getRoots();
|
||||
for (VirtualFile root : affectedRoots) {
|
||||
try {
|
||||
Pair<String, String> nameAndEmail = getUserNameAndEmailFromGitConfig(project, root);
|
||||
String name = nameAndEmail.getFirst();
|
||||
String email = nameAndEmail.getSecond();
|
||||
if (name == null || email == null) {
|
||||
notDefined.add(root);
|
||||
}
|
||||
else {
|
||||
defined.put(root, nameAndEmail);
|
||||
}
|
||||
}
|
||||
catch (VcsException e) {
|
||||
LOG.error("Couldn't get user.name and user.email for root " + root, e);
|
||||
// doing nothing - let commit with possibly empty user.name/email
|
||||
}
|
||||
}
|
||||
|
||||
if (notDefined.isEmpty()) {
|
||||
return ReturnResult.COMMIT;
|
||||
}
|
||||
|
||||
if (defined.isEmpty() && allRoots.size() > affectedRoots.size()) {
|
||||
allRoots.removeAll(affectedRoots);
|
||||
for (VirtualFile root : allRoots) {
|
||||
try {
|
||||
Pair<String, String> nameAndEmail = getUserNameAndEmailFromGitConfig(project, root);
|
||||
String name = nameAndEmail.getFirst();
|
||||
String email = nameAndEmail.getSecond();
|
||||
if (name != null && email != null) {
|
||||
defined.put(root, nameAndEmail);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (VcsException e) {
|
||||
LOG.error("Couldn't get user.name and user.email for root " + root, e);
|
||||
// doing nothing - not critical not to find the values for other roots not affected by commit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GitUserNameNotDefinedDialog dialog = new GitUserNameNotDefinedDialog(project, notDefined, affectedRoots, defined);
|
||||
dialog.show();
|
||||
if (dialog.isOK()) {
|
||||
try {
|
||||
if (dialog.isGlobal()) {
|
||||
GitConfigUtil.setValue(project, notDefined.iterator().next(), GitConfigUtil.USER_NAME, dialog.getUserName(), "--global");
|
||||
GitConfigUtil.setValue(project, notDefined.iterator().next(), GitConfigUtil.USER_EMAIL, dialog.getUserEmail(), "--global");
|
||||
}
|
||||
else {
|
||||
for (VirtualFile root : notDefined) {
|
||||
GitConfigUtil.setValue(project, root, GitConfigUtil.USER_NAME, dialog.getUserName());
|
||||
GitConfigUtil.setValue(project, root, GitConfigUtil.USER_EMAIL, dialog.getUserEmail());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (VcsException e) {
|
||||
String message = "Couldn't set user.name and user.email";
|
||||
LOG.error(message, e);
|
||||
Messages.showErrorDialog(myPanel.getComponent(), message);
|
||||
return ReturnResult.CANCEL;
|
||||
}
|
||||
return ReturnResult.COMMIT;
|
||||
}
|
||||
return ReturnResult.CLOSE_WINDOW;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Pair<String, String> getUserNameAndEmailFromGitConfig(@NotNull Project project, @NotNull VirtualFile root) throws VcsException {
|
||||
String name = GitConfigUtil.getValue(project, root, GitConfigUtil.USER_NAME);
|
||||
String email = GitConfigUtil.getValue(project, root, GitConfigUtil.USER_EMAIL);
|
||||
return Pair.create(name, email);
|
||||
}
|
||||
|
||||
private boolean emptyCommitMessage() {
|
||||
if (myPanel.getCommitMessage().trim().isEmpty()) {
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package git4idea.checkin;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.components.JBCheckBox;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.intellij.util.ui.GridBag;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.intellij.openapi.util.text.StringUtil.isEmptyOrSpaces;
|
||||
import static com.intellij.util.ui.UIUtil.DEFAULT_HGAP;
|
||||
import static com.intellij.util.ui.UIUtil.DEFAULT_VGAP;
|
||||
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
class GitUserNameNotDefinedDialog extends DialogWrapper {
|
||||
|
||||
@NotNull private final Collection<VirtualFile> myRootsWithUndefinedProps;
|
||||
@NotNull private final Collection<VirtualFile> myAllRootsAffectedByCommit;
|
||||
@Nullable private final Pair<String,String> myProposedValues;
|
||||
|
||||
private JTextField myNameTextField;
|
||||
private JTextField myEmailTextField;
|
||||
private JBCheckBox myGlobalCheckbox;
|
||||
|
||||
GitUserNameNotDefinedDialog(@NotNull Project project,
|
||||
@NotNull Collection<VirtualFile> rootsWithUndefinedProps,
|
||||
@NotNull Collection<VirtualFile> allRootsAffectedByCommit,
|
||||
@NotNull Map<VirtualFile, Pair<String, String>> rootsWithDefinedProps) {
|
||||
super(project, false);
|
||||
myRootsWithUndefinedProps = rootsWithUndefinedProps;
|
||||
myAllRootsAffectedByCommit = allRootsAffectedByCommit;
|
||||
|
||||
myProposedValues = calcProposedValues(rootsWithDefinedProps);
|
||||
|
||||
setTitle("Git User Name Is Not Defined");
|
||||
setOKButtonText("Set and Commit");
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ValidationInfo doValidate() {
|
||||
String message = "You have to specify user name and email for Git";
|
||||
if (isEmptyOrSpaces(getUserName())) {
|
||||
return new ValidationInfo(message, myNameTextField);
|
||||
}
|
||||
if (isEmptyOrSpaces(getUserEmail())) {
|
||||
return new ValidationInfo(message, myEmailTextField);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myNameTextField;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Pair<String, String> calcProposedValues(Map<VirtualFile, Pair<String, String>> rootsWithDefinedProps) {
|
||||
if (rootsWithDefinedProps.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Iterator<Map.Entry<VirtualFile,Pair<String,String>>> iterator = rootsWithDefinedProps.entrySet().iterator();
|
||||
Pair<String, String> firstValue = iterator.next().getValue();
|
||||
while (iterator.hasNext()) {
|
||||
// nothing to propose if there are different values set in different repositories
|
||||
if (!firstValue.equals(iterator.next().getValue())) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return firstValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
|
||||
JLabel icon = new JLabel(UIUtil.getWarningIcon(), SwingConstants.LEFT);
|
||||
JLabel description = new JLabel(getMessageText());
|
||||
|
||||
myNameTextField = new JTextField(20);
|
||||
JBLabel nameLabel = new JBLabel("Name: ");
|
||||
nameLabel.setDisplayedMnemonic('n');
|
||||
nameLabel.setLabelFor(myNameTextField);
|
||||
|
||||
myEmailTextField = new JTextField(20);
|
||||
JBLabel emailLabel = new JBLabel("E-mail: ");
|
||||
emailLabel.setDisplayedMnemonic('e');
|
||||
emailLabel.setLabelFor(myEmailTextField);
|
||||
|
||||
if (myProposedValues != null) {
|
||||
myNameTextField.setText(myProposedValues.getFirst());
|
||||
myEmailTextField.setText(myProposedValues.getSecond());
|
||||
}
|
||||
else {
|
||||
myNameTextField.setText(SystemProperties.getUserName());
|
||||
}
|
||||
|
||||
myGlobalCheckbox = new JBCheckBox("Set properties globally", true);
|
||||
myGlobalCheckbox.setMnemonic('g');
|
||||
|
||||
JPanel rootPanel = new JPanel(new GridBagLayout());
|
||||
GridBag g = new GridBag()
|
||||
.setDefaultInsets(new Insets(0, 0, DEFAULT_VGAP, DEFAULT_HGAP))
|
||||
.setDefaultAnchor(GridBagConstraints.LINE_START)
|
||||
.setDefaultFill(GridBagConstraints.HORIZONTAL);
|
||||
|
||||
rootPanel.add(description, g.nextLine().next().coverLine(3).pady(DEFAULT_HGAP));
|
||||
rootPanel.add(icon, g.nextLine().next().coverColumn(3));
|
||||
rootPanel.add(nameLabel, g.next().fillCellNone().insets(new Insets(0, 6, DEFAULT_VGAP, DEFAULT_HGAP)));
|
||||
rootPanel.add(myNameTextField, g.next());
|
||||
rootPanel.add(emailLabel, g.nextLine().next().next().fillCellNone().insets(new Insets(0, 6, DEFAULT_VGAP, DEFAULT_HGAP)));
|
||||
rootPanel.add(myEmailTextField, g.next());
|
||||
rootPanel.add(myGlobalCheckbox, g.nextLine().next().next().coverLine(2));
|
||||
|
||||
return rootPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createNorthPanel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getMessageText() {
|
||||
if (myAllRootsAffectedByCommit.size() == myRootsWithUndefinedProps.size()) {
|
||||
return "";
|
||||
}
|
||||
String text = "Git user.name and user.email properties are not defined in " + StringUtil.pluralize("root", myRootsWithUndefinedProps.size()) + "<br/>";
|
||||
for (VirtualFile root : myRootsWithUndefinedProps) {
|
||||
text += root.getPresentableUrl() + "<br/>";
|
||||
}
|
||||
return "<html>" + text + "</html>";
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return myNameTextField.getText();
|
||||
}
|
||||
|
||||
public String getUserEmail() {
|
||||
return myEmailTextField.getText();
|
||||
}
|
||||
|
||||
public boolean isGlobal() {
|
||||
return myGlobalCheckbox.isSelected();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class GitConfigUtil {
|
||||
public static final String USER_NAME = "user.name";
|
||||
public static final String USER_EMAIL = "user.email";
|
||||
|
||||
/**
|
||||
* A private constructor for utility class
|
||||
@@ -240,11 +241,12 @@ public class GitConfigUtil {
|
||||
* @param value the value to set
|
||||
* @throws VcsException if there is a problem with running git
|
||||
*/
|
||||
public static void setValue(Project project, VirtualFile root, String key, String value) throws VcsException {
|
||||
public static void setValue(Project project, VirtualFile root, String key, String value, String... additionalParameters) throws VcsException {
|
||||
GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.CONFIG);
|
||||
h.setNoSSH(true);
|
||||
h.setSilent(true);
|
||||
h.ignoreErrorCode(1);
|
||||
h.addParameters(additionalParameters);
|
||||
h.addParameters(key, value);
|
||||
h.run();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user