mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[git] Restrict the ability to force push
* Introduce a checkbox in the settings which hides the "Force push" button by default. * Let define a list of patterns of branches which are "protected" from the force pushing: the force push button will be disabled if such branches are selected as push targets. Relates to IDEA-85773.
This commit is contained in:
@@ -28,13 +28,12 @@ import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.options.SearchableConfigurable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.Gray;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.RawCommandLineEditor;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtilRt;
|
||||
import com.intellij.util.execution.ParametersListUtil;
|
||||
import com.intellij.xml.util.XmlStringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -48,23 +47,6 @@ import static com.intellij.compiler.options.CompilerOptionsFilter.Setting;
|
||||
public class CompilerUIConfigurable implements SearchableConfigurable, Configurable.NoScroll {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.options.CompilerUIConfigurable");
|
||||
|
||||
public static final Function<String, List<String>> LINE_PARSER = new Function<String, List<String>>() {
|
||||
@Override
|
||||
public List<String> fun(String text) {
|
||||
final ArrayList<String> result = ContainerUtilRt.newArrayList();
|
||||
final StringTokenizer tokenizer = new StringTokenizer(text, ";", false);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
result.add(tokenizer.nextToken());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
public static final Function<List<String>, String> LINE_JOINER = new Function<List<String>, String>() {
|
||||
@Override
|
||||
public String fun(List<String> strings) {
|
||||
return StringUtil.join(strings, ";");
|
||||
}
|
||||
};
|
||||
private static final Set<Setting> EXTERNAL_BUILD_SETTINGS = EnumSet.of(
|
||||
Setting.EXTERNAL_BUILD, Setting.AUTO_MAKE, Setting.PARALLEL_COMPILATION, Setting.REBUILD_MODULE_ON_DEPENDENCY_CHANGE,
|
||||
Setting.HEAP_SIZE, Setting.COMPILER_VM_OPTIONS
|
||||
@@ -327,7 +309,7 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura
|
||||
}
|
||||
|
||||
private void createUIComponents() {
|
||||
myResourcePatternsField = new RawCommandLineEditor(LINE_PARSER, LINE_JOINER);
|
||||
myResourcePatternsField = new RawCommandLineEditor(ParametersListUtil.COLON_LINE_PARSER, ParametersListUtil.COLON_LINE_JOINER);
|
||||
myResourcePatternsField.setDialogCaption("Resource patterns");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,4 +69,20 @@ public abstract class PushSupport<Repo extends Repository, Source extends PushSo
|
||||
public boolean shouldRequestIncomingChangesForNotCheckedRepositories() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if force push is allowed now in the selected repository.
|
||||
* <p/>
|
||||
* Force push may be completely disabled for the project which is checked by {@link #isForcePushEnabled()},
|
||||
* or it might depend e.g. on the branch user is pushing to.
|
||||
*/
|
||||
public abstract boolean isForcePushAllowed(@NotNull Repo repo, Target target);
|
||||
|
||||
/**
|
||||
* Checks if force push is allowed for this VCS at all.
|
||||
* <p/>
|
||||
* If it is not allowed for all PushSupports in the project, the "Force Push" button will be invisible.
|
||||
*/
|
||||
public abstract boolean isForcePushEnabled();
|
||||
|
||||
}
|
||||
|
||||
@@ -79,6 +79,24 @@ public class PushController implements Disposable {
|
||||
selectFirstChecked();
|
||||
}
|
||||
|
||||
public boolean isForcePushEnabled() {
|
||||
return ContainerUtil.exists(myView2Model.values(), new Condition<MyRepoModel>() {
|
||||
@Override
|
||||
public boolean value(MyRepoModel model) {
|
||||
return model.getSupport().isForcePushEnabled();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isForcePushAllowed() {
|
||||
return ContainerUtil.exists(myView2Model.values(), new Condition<MyRepoModel>() {
|
||||
@Override
|
||||
public boolean value(MyRepoModel model) {
|
||||
return model.isSelected() && model.getSupport().isForcePushAllowed(model.getRepository(), model.getTarget());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void selectFirstChecked() {
|
||||
Map.Entry<RepositoryNode, MyRepoModel> selected =
|
||||
ContainerUtil.find(myView2Model.entrySet(), new Condition<Map.Entry<RepositoryNode, MyRepoModel>>() {
|
||||
|
||||
@@ -41,10 +41,10 @@ public class VcsPushDialog extends DialogWrapper {
|
||||
@NotNull private final Project myProject;
|
||||
private final PushLog myListPanel;
|
||||
private final PushController myController;
|
||||
private final Action[] myExecutorActions = {new DvcsPushAction("&Force Push", true)};
|
||||
@NotNull private final JPanel myAdditionalOptionsFromVcsPanel;
|
||||
|
||||
private DvcsPushAction myPushAction;
|
||||
private Action myPushAction;
|
||||
@Nullable private ForcePushAction myForcePushAction;
|
||||
|
||||
public VcsPushDialog(@NotNull Project project, @NotNull List<? extends Repository> selectedRepositories) {
|
||||
super(project);
|
||||
@@ -60,7 +60,6 @@ public class VcsPushDialog extends DialogWrapper {
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
|
||||
JComponent rootPanel = new JPanel(new BorderLayout(0, 15));
|
||||
rootPanel.add(myListPanel, BorderLayout.CENTER);
|
||||
for (VcsPushOptionsPanel panel : myController.getAdditionalPanels()) {
|
||||
@@ -79,10 +78,16 @@ public class VcsPushDialog extends DialogWrapper {
|
||||
@NotNull
|
||||
protected Action[] createActions() {
|
||||
final List<Action> actions = new ArrayList<Action>();
|
||||
myPushAction = new DvcsPushAction("&Push", false);
|
||||
if (myController.isForcePushEnabled()) {
|
||||
myForcePushAction = new ForcePushAction();
|
||||
myForcePushAction.setEnabled(myController.isForcePushAllowed());
|
||||
myPushAction = new ComplexPushAction(myForcePushAction);
|
||||
}
|
||||
else {
|
||||
myPushAction = new SimplePushAction();
|
||||
}
|
||||
myPushAction.putValue(DEFAULT_ACTION, Boolean.TRUE);
|
||||
actions.add(myPushAction);
|
||||
myPushAction.setOptions(myExecutorActions);
|
||||
actions.add(getCancelAction());
|
||||
actions.add(getHelpAction());
|
||||
return actions.toArray(new Action[actions.size()]);
|
||||
@@ -112,6 +117,9 @@ public class VcsPushDialog extends DialogWrapper {
|
||||
}
|
||||
|
||||
public void updateButtons() {
|
||||
if (myForcePushAction != null) {
|
||||
myForcePushAction.setEnabled(myController.isForcePushAllowed());
|
||||
}
|
||||
initValidation();
|
||||
}
|
||||
|
||||
@@ -120,13 +128,39 @@ public class VcsPushDialog extends DialogWrapper {
|
||||
return false;
|
||||
}
|
||||
|
||||
private class DvcsPushAction extends AbstractAction implements OptionAction {
|
||||
private Action[] myOptions = new Action[0];
|
||||
private final boolean myForce;
|
||||
private class SimplePushAction extends AbstractAction {
|
||||
SimplePushAction() {
|
||||
super("&Push");
|
||||
}
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
myController.push(false);
|
||||
close(OK_EXIT_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
private DvcsPushAction(String title, boolean force) {
|
||||
super(title);
|
||||
myForce = force;
|
||||
private class ForcePushAction extends AbstractAction {
|
||||
ForcePushAction() {
|
||||
super("&Force Push");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int answer = Messages.showOkCancelDialog(myProject,
|
||||
"You're going to force push. It will overwrite commits at the remote. Are you sure you want to proceed?",
|
||||
"Force Push", "&Force Push", CommonBundle.getCancelButtonText(), Messages.getWarningIcon());
|
||||
if (answer == OK) {
|
||||
myController.push(true);
|
||||
close(OK_EXIT_CODE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ComplexPushAction extends SimplePushAction implements OptionAction {
|
||||
private final Action[] myOptions;
|
||||
|
||||
private ComplexPushAction(Action additionalAction) {
|
||||
myOptions = new Action[] { additionalAction };
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -137,31 +171,11 @@ public class VcsPushDialog extends DialogWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (myForce) {
|
||||
int answer = Messages.showOkCancelDialog(myProject, getConfirmationMessage(),
|
||||
"Force Push",
|
||||
"&Force Push", CommonBundle.getCancelButtonText(), Messages.getWarningIcon());
|
||||
if (answer != OK) return;
|
||||
}
|
||||
myController.push(myForce);
|
||||
close(OK_EXIT_CODE);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Action[] getOptions() {
|
||||
return myOptions;
|
||||
}
|
||||
|
||||
public void setOptions(Action[] actions) {
|
||||
myOptions = actions;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getConfirmationMessage() {
|
||||
return "You're going to force push. It will overwrite commits at the remote. Are you sure you want to proceed?";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
@@ -41,6 +42,23 @@ public class ParametersListUtil {
|
||||
return StringUtil.join(strings, " ");
|
||||
}
|
||||
};
|
||||
public static final Function<String, List<String>> COLON_LINE_PARSER = new Function<String, List<String>>() {
|
||||
@Override
|
||||
public List<String> fun(String text) {
|
||||
final ArrayList<String> result = ContainerUtilRt.newArrayList();
|
||||
final StringTokenizer tokenizer = new StringTokenizer(text, ";", false);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
result.add(tokenizer.nextToken());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
public static final Function<List<String>, String> COLON_LINE_JOINER = new Function<List<String>, String>() {
|
||||
@Override
|
||||
public String fun(List<String> strings) {
|
||||
return StringUtil.join(strings, ";");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* <p>Joins list of parameters into single string, which may be then parsed back into list by {@link #parseToArray(String)}.</p>
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
<projectService
|
||||
serviceInterface="git4idea.config.GitVcsSettings"
|
||||
serviceImplementation="git4idea.config.GitVcsSettings"/>
|
||||
<projectService serviceImplementation="git4idea.config.GitSharedSettings" />
|
||||
<projectService
|
||||
serviceInterface="git4idea.settings.GitPushSettings"
|
||||
serviceImplementation="git4idea.settings.GitPushSettings"/>
|
||||
|
||||
@@ -173,7 +173,8 @@ public class GitVcs extends AbstractVcs<CommittedChangeList> {
|
||||
@NotNull final GitHistoryProvider gitHistoryProvider,
|
||||
@NotNull final GitRollbackEnvironment gitRollbackEnvironment,
|
||||
@NotNull final GitVcsApplicationSettings gitSettings,
|
||||
@NotNull final GitVcsSettings gitProjectSettings) {
|
||||
@NotNull final GitVcsSettings gitProjectSettings,
|
||||
@NotNull GitSharedSettings sharedSettings) {
|
||||
super(project, NAME);
|
||||
myGit = git;
|
||||
myVcsManager = gitVcsManager;
|
||||
@@ -185,7 +186,7 @@ public class GitVcs extends AbstractVcs<CommittedChangeList> {
|
||||
myHistoryProvider = gitHistoryProvider;
|
||||
myRollbackEnvironment = gitRollbackEnvironment;
|
||||
myRevSelector = new GitRevisionSelector();
|
||||
myConfigurable = new GitVcsConfigurable(gitProjectSettings, myProject);
|
||||
myConfigurable = new GitVcsConfigurable(myProject, gitProjectSettings, sharedSettings);
|
||||
myUpdateEnvironment = new GitUpdateEnvironment(myProject, this, gitProjectSettings);
|
||||
myCommittedChangeListProvider = new GitCommittedChangeListProvider(myProject);
|
||||
myOutgoingChangesProvider = new GitOutgoingChangesProvider(myProject);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.config;
|
||||
|
||||
import com.intellij.openapi.components.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@State(
|
||||
name = "GitSharedSettings",
|
||||
storages = {
|
||||
@Storage(file = StoragePathMacros.PROJECT_FILE),
|
||||
@Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/vcs.xml", scheme = StorageScheme.DIRECTORY_BASED)
|
||||
})
|
||||
public class GitSharedSettings implements PersistentStateComponent<GitSharedSettings.State> {
|
||||
|
||||
public static class State {
|
||||
public List<String> FORCE_PUSH_PROHIBITED_PATTERNS = Arrays.asList("master");
|
||||
}
|
||||
|
||||
private State myState = new State();
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public State getState() {
|
||||
return myState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(State state) {
|
||||
myState = state;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getForcePushProhibitedPatterns() {
|
||||
return Collections.unmodifiableList(myState.FORCE_PUSH_PROHIBITED_PATTERNS);
|
||||
}
|
||||
|
||||
public void setForcePushProhibitedPatters(@NotNull List<String> patterns) {
|
||||
myState.FORCE_PUSH_PROHIBITED_PATTERNS = new ArrayList<String>(patterns);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,11 +28,13 @@ public class GitVcsConfigurable implements Configurable {
|
||||
|
||||
private final Project myProject;
|
||||
private final GitVcsSettings mySettings;
|
||||
@NotNull private final GitSharedSettings mySharedSettings;
|
||||
private GitVcsPanel panel;
|
||||
|
||||
public GitVcsConfigurable(@NotNull GitVcsSettings settings, @NotNull Project project) {
|
||||
public GitVcsConfigurable(@NotNull Project project, @NotNull GitVcsSettings settings, @NotNull GitSharedSettings sharedSettings) {
|
||||
myProject = project;
|
||||
mySettings = settings;
|
||||
mySharedSettings = sharedSettings;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -51,23 +53,23 @@ public class GitVcsConfigurable implements Configurable {
|
||||
@Override
|
||||
public JComponent createComponent() {
|
||||
panel = new GitVcsPanel(myProject);
|
||||
panel.load(mySettings);
|
||||
panel.load(mySettings, mySharedSettings);
|
||||
return panel.getPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModified() {
|
||||
return panel.isModified(mySettings);
|
||||
return panel.isModified(mySettings, mySharedSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply() throws ConfigurationException {
|
||||
panel.save(mySettings);
|
||||
panel.save(mySettings, mySharedSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
panel.load(mySettings);
|
||||
panel.load(mySettings, mySharedSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
<grid id="4d15a" layout-manager="GridLayoutManager" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<grid id="4d15a" layout-manager="GridLayoutManager" row-count="6" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
@@ -101,7 +101,7 @@
|
||||
<children>
|
||||
<component id="9d661" class="javax.swing.JCheckBox" binding="myAutoUpdateIfPushRejected">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
<grid row="1" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<iconTextGap value="4"/>
|
||||
@@ -110,7 +110,7 @@
|
||||
</component>
|
||||
<component id="2e80d" class="com.intellij.ui.components.JBCheckBox" binding="mySyncBranchControl">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
<grid row="2" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Control &branches from different roots synchronously"/>
|
||||
@@ -119,7 +119,7 @@
|
||||
</component>
|
||||
<component id="5a98" class="javax.swing.JCheckBox" binding="myAutoCommitOnCherryPick">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
<grid row="0" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<iconTextGap value="4"/>
|
||||
@@ -128,7 +128,7 @@
|
||||
</component>
|
||||
<component id="1ad55" class="com.intellij.ui.components.JBCheckBox" binding="myWarnAboutCrlf" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
<grid row="3" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Warn if &CRLF line separators are about to be committed"/>
|
||||
@@ -136,13 +136,38 @@
|
||||
</component>
|
||||
<component id="29d5c" class="javax.swing.JCheckBox" binding="myWarnAboutDetachedHead">
|
||||
<constraints>
|
||||
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
<grid row="4" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<selected value="true"/>
|
||||
<text value="Warn when committing in detached HEAD or during rebase"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="885e3" class="javax.swing.JCheckBox" binding="myEnableForcePush">
|
||||
<constraints>
|
||||
<grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<selected value="true"/>
|
||||
<text value="Allow &force push"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="b0317" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myProtectedBranchesButton" custom-create="true" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="5" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value=""/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="e7b92" class="com.intellij.ui.components.JBLabel" binding="myProtectedBranchesLabel">
|
||||
<constraints>
|
||||
<grid row="5" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Protected branches:"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package git4idea.config;
|
||||
|
||||
import com.intellij.dvcs.branch.DvcsBranchSync;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
|
||||
@@ -23,6 +24,9 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||
import com.intellij.ui.components.JBCheckBox;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.execution.ParametersListUtil;
|
||||
import git4idea.GitVcs;
|
||||
import git4idea.i18n.GitBundle;
|
||||
import git4idea.repo.GitRepositoryManager;
|
||||
@@ -31,6 +35,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Git VCS configuration panel
|
||||
@@ -52,6 +57,9 @@ public class GitVcsPanel {
|
||||
private JCheckBox myAutoCommitOnCherryPick;
|
||||
private JBCheckBox myWarnAboutCrlf;
|
||||
private JCheckBox myWarnAboutDetachedHead;
|
||||
private JCheckBox myEnableForcePush;
|
||||
private TextFieldWithBrowseButton myProtectedBranchesButton;
|
||||
private JBLabel myProtectedBranchesLabel;
|
||||
|
||||
public GitVcsPanel(@NotNull Project project) {
|
||||
myVcs = GitVcs.getInstance(project);
|
||||
@@ -70,6 +78,7 @@ public class GitVcsPanel {
|
||||
FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor());
|
||||
final GitRepositoryManager repositoryManager = ServiceManager.getService(project, GitRepositoryManager.class);
|
||||
mySyncBranchControl.setVisible(repositoryManager != null && repositoryManager.moreThanOneRoot());
|
||||
myProtectedBranchesLabel.setLabelFor(myProtectedBranchesButton);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,7 +124,7 @@ public class GitVcsPanel {
|
||||
*
|
||||
* @param settings the settings to load
|
||||
*/
|
||||
public void load(@NotNull GitVcsSettings settings) {
|
||||
public void load(@NotNull GitVcsSettings settings, @NotNull GitSharedSettings sharedSettings) {
|
||||
myGitField.setText(settings.getAppSettings().getPathToGit());
|
||||
mySSHExecutableComboBox.setSelectedItem(settings.isIdeaSsh() ? IDEA_SSH : NATIVE_SSH);
|
||||
myAutoUpdateIfPushRejected.setSelected(settings.autoUpdateIfPushRejected());
|
||||
@@ -123,6 +132,8 @@ public class GitVcsPanel {
|
||||
myAutoCommitOnCherryPick.setSelected(settings.isAutoCommitOnCherryPick());
|
||||
myWarnAboutCrlf.setSelected(settings.warnAboutCrlf());
|
||||
myWarnAboutDetachedHead.setSelected(settings.warnAboutDetachedHead());
|
||||
myEnableForcePush.setSelected(settings.isForcePushAllowed());
|
||||
myProtectedBranchesButton.setText(ParametersListUtil.COLON_LINE_JOINER.fun(sharedSettings.getForcePushProhibitedPatterns()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,14 +141,17 @@ public class GitVcsPanel {
|
||||
*
|
||||
* @param settings the settings to load
|
||||
*/
|
||||
public boolean isModified(@NotNull GitVcsSettings settings) {
|
||||
public boolean isModified(@NotNull GitVcsSettings settings, @NotNull GitSharedSettings sharedSettings) {
|
||||
return !settings.getAppSettings().getPathToGit().equals(getCurrentExecutablePath()) ||
|
||||
(settings.isIdeaSsh() != IDEA_SSH.equals(mySSHExecutableComboBox.getSelectedItem())) ||
|
||||
!settings.autoUpdateIfPushRejected() == myAutoUpdateIfPushRejected.isSelected() ||
|
||||
((settings.getSyncSetting() == DvcsBranchSync.SYNC) != mySyncBranchControl.isSelected() ||
|
||||
settings.isAutoCommitOnCherryPick() != myAutoCommitOnCherryPick.isSelected() ||
|
||||
settings.warnAboutCrlf() != myWarnAboutCrlf.isSelected() ||
|
||||
settings.warnAboutDetachedHead() != myWarnAboutDetachedHead.isSelected());
|
||||
settings.warnAboutDetachedHead() != myWarnAboutDetachedHead.isSelected() ||
|
||||
settings.isForcePushAllowed() != myEnableForcePush.isSelected() ||
|
||||
!ContainerUtil.sorted(sharedSettings.getForcePushProhibitedPatterns()).equals(
|
||||
ContainerUtil.sorted(getProtectedBranchesPatterns())));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,7 +159,7 @@ public class GitVcsPanel {
|
||||
*
|
||||
* @param settings the settings object
|
||||
*/
|
||||
public void save(@NotNull GitVcsSettings settings) {
|
||||
public void save(@NotNull GitVcsSettings settings, GitSharedSettings sharedSettings) {
|
||||
settings.getAppSettings().setPathToGit(getCurrentExecutablePath());
|
||||
myVcs.checkVersion();
|
||||
settings.getAppSettings().setIdeaSsh(IDEA_SSH.equals(mySSHExecutableComboBox.getSelectedItem()) ?
|
||||
@@ -157,6 +171,23 @@ public class GitVcsPanel {
|
||||
settings.setAutoCommitOnCherryPick(myAutoCommitOnCherryPick.isSelected());
|
||||
settings.setWarnAboutCrlf(myWarnAboutCrlf.isSelected());
|
||||
settings.setWarnAboutDetachedHead(myWarnAboutDetachedHead.isSelected());
|
||||
settings.setForcePushAllowed(myEnableForcePush.isSelected());
|
||||
sharedSettings.setForcePushProhibitedPatters(getProtectedBranchesPatterns());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<String> getProtectedBranchesPatterns() {
|
||||
return ParametersListUtil.COLON_LINE_PARSER.fun(myProtectedBranchesButton.getText());
|
||||
}
|
||||
|
||||
private void createUIComponents() {
|
||||
myProtectedBranchesButton = new TextFieldWithBrowseButton.NoPathCompletion(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Messages.showTextAreaDialog(myProtectedBranchesButton.getTextField(), "Protected Branches", "Git.Force.Push.Protected.Branches",
|
||||
ParametersListUtil.COLON_LINE_PARSER, ParametersListUtil.COLON_LINE_JOINER);
|
||||
}
|
||||
});
|
||||
myProtectedBranchesButton.setButtonIcon(AllIcons.Actions.ShowViewer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
|
||||
public boolean WARN_ABOUT_CRLF = true;
|
||||
public boolean WARN_ABOUT_DETACHED_HEAD = true;
|
||||
public GitResetMode RESET_MODE = null;
|
||||
public boolean FORCE_PUSH_ALLOWED = false;
|
||||
}
|
||||
|
||||
public GitVcsSettings(GitVcsApplicationSettings appSettings) {
|
||||
@@ -201,6 +202,14 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
|
||||
myState.RESET_MODE = mode;
|
||||
}
|
||||
|
||||
public boolean isForcePushAllowed() {
|
||||
return myState.FORCE_PUSH_ALLOWED;
|
||||
}
|
||||
|
||||
public void setForcePushAllowed(boolean allowed) {
|
||||
myState.FORCE_PUSH_ALLOWED = allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides migration from project settings.
|
||||
* This method is to be removed in IDEA 13: it should be moved to {@link GitVcsApplicationSettings}
|
||||
|
||||
@@ -20,12 +20,17 @@ import com.intellij.dvcs.push.PushSupport;
|
||||
import com.intellij.dvcs.push.PushTargetPanel;
|
||||
import com.intellij.dvcs.push.Pusher;
|
||||
import com.intellij.dvcs.repo.RepositoryManager;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.vcs.AbstractVcs;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import git4idea.*;
|
||||
import git4idea.branch.GitBranchUtil;
|
||||
import git4idea.config.GitSharedSettings;
|
||||
import git4idea.config.GitVcsSettings;
|
||||
import git4idea.repo.GitBranchTrackInfo;
|
||||
import git4idea.repo.GitRemote;
|
||||
import git4idea.repo.GitRepository;
|
||||
@@ -43,6 +48,8 @@ public class GitPushSupport extends PushSupport<GitRepository, GitPushSource, Gi
|
||||
@NotNull private final GitVcs myVcs;
|
||||
@NotNull private final Pusher<GitRepository, GitPushSource, GitPushTarget> myPusher;
|
||||
@NotNull private final OutgoingCommitsProvider<GitRepository, GitPushSource, GitPushTarget> myOutgoingCommitsProvider;
|
||||
@NotNull private final GitVcsSettings mySettings;
|
||||
private final GitSharedSettings mySharedSettings;
|
||||
|
||||
// instantiated from plugin.xml
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@@ -51,6 +58,8 @@ public class GitPushSupport extends PushSupport<GitRepository, GitPushSource, Gi
|
||||
myVcs = ObjectUtils.assertNotNull(GitVcs.getInstance(project));
|
||||
myPusher = new GitPusher(project);
|
||||
myOutgoingCommitsProvider = new GitOutgoingCommitsProvider(project);
|
||||
mySettings = GitVcsSettings.getInstance(project);
|
||||
mySharedSettings = ServiceManager.getService(project, GitSharedSettings.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -131,4 +140,20 @@ public class GitPushSupport extends PushSupport<GitRepository, GitPushSource, Gi
|
||||
return new GitPushTargetPanel(repository, defaultTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForcePushAllowed(@NotNull GitRepository repo, @NotNull GitPushTarget target) {
|
||||
final String targetBranch = target.getBranch().getNameForRemoteOperations();
|
||||
return !ContainerUtil.exists(mySharedSettings.getForcePushProhibitedPatterns(), new Condition<String>() {
|
||||
@Override
|
||||
public boolean value(String pattern) {
|
||||
return targetBranch.matches("^" + pattern + "$"); // let "master" match only "master" and not "any-master-here" by default
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForcePushEnabled() {
|
||||
return mySettings.isForcePushAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.zmlx.hg4idea.push;
|
||||
|
||||
import com.intellij.dvcs.push.*;
|
||||
import com.intellij.dvcs.repo.Repository;
|
||||
import com.intellij.dvcs.repo.RepositoryManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.AbstractVcs;
|
||||
@@ -85,6 +86,16 @@ public class HgPushSupport extends PushSupport<HgRepository, HgPushSource, HgTar
|
||||
return new HgPushTargetPanel(repository, defaultTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForcePushAllowed(@NotNull HgRepository repo, @NotNull HgTarget target) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForcePushEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRequestIncomingChangesForNotCheckedRepositories() {
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user