diff options
author | Alexander Nittka | 2020-01-04 19:31:15 +0000 |
---|---|---|
committer | Thomas Wolf | 2020-02-25 07:14:02 +0000 |
commit | 1205b4b3e62d5622378c20576e1582f9155c677c (patch) | |
tree | 2e076c0dd3991f6109bf052e9c91e10f3c7d9c81 | |
parent | 97385df3e09c3351760e6f6ca415438ca1dba786 (diff) | |
download | egit-1205b4b3e62d5622378c20576e1582f9155c677c.tar.gz egit-1205b4b3e62d5622378c20576e1582f9155c677c.tar.xz egit-1205b4b3e62d5622378c20576e1582f9155c677c.zip |
Create branch from repository group
Allow creating a new branch for a mixed selections of repositories
and/or repository groups. The branch is created from the current
head. Except for the branch name no further configuration is
possible.
Bug: 558561
Change-Id: Ic6dccb6d9813ee568c70997d997f92121de46752
Signed-off-by: Alexander Nittka <alex@nittka.de>
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
5 files changed, 145 insertions, 14 deletions
diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/actions/SwitchToMenuTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/actions/SwitchToMenuTest.java index 7448f0bc80..6e10462354 100644 --- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/actions/SwitchToMenuTest.java +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/actions/SwitchToMenuTest.java @@ -209,13 +209,15 @@ public class SwitchToMenuTest extends LocalRepositoryTestCase { mockMultiProjectSelection(PROJ1, PROJ2); MenuItem[] items = fillMenu(); - assertTextEquals("change/15", items[0]); - assertTextEquals("change/16", items[1]); - assertTextEquals("change/17", items[2]); - assertTextEquals("change/18", items[3]); - assertTextEquals("change/19", items[4]); - assertTextEquals("master", items[5]); - assertTextEquals("stable", items[6]); + assertTextEquals(UIText.SwitchToMenu_NewBranchMenuLabel, items[0]); + // item[1] is separator + assertTextEquals("change/15", items[2]); + assertTextEquals("change/16", items[3]); + assertTextEquals("change/17", items[4]); + assertTextEquals("change/18", items[5]); + assertTextEquals("change/19", items[6]); + assertTextEquals("master", items[7]); + assertTextEquals("stable", items[8]); } @Test @@ -273,7 +275,9 @@ public class SwitchToMenuTest extends LocalRepositoryTestCase { mockMultiProjectSelection(PROJ1, PROJ2); MenuItem[] items = fillMenu(); - assertTextEquals(UIText.SwitchToMenu_NoCommonBranchesFound, items[0]); + assertTextEquals(UIText.SwitchToMenu_NewBranchMenuLabel, items[0]); + // item[1] is separator + assertTextEquals(UIText.SwitchToMenu_NoCommonBranchesFound, items[2]); // delete reflog again to not confuse other tests new File(gitOne, Constants.LOGS + "/" + Constants.HEAD).delete(); diff --git a/org.eclipse.egit.ui/plugin.xml b/org.eclipse.egit.ui/plugin.xml index 7a60e571c3..4f75930cb6 100644 --- a/org.eclipse.egit.ui/plugin.xml +++ b/org.eclipse.egit.ui/plugin.xml @@ -4251,6 +4251,9 @@ <and> <or> <instanceof + value="org.eclipse.egit.ui.internal.repository.tree.RepositoryGroupNode"> + </instanceof> + <instanceof value="org.eclipse.egit.ui.internal.repository.tree.RepositoryNode"> </instanceof> <instanceof @@ -4263,6 +4266,9 @@ <test property="GitRepository.isBare" value="false" /> </and> </iterate> + <test + property="GitSelection.selectionMultipleRepositories" value="false"> + </test> </and> </visibleWhen> </menu> diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java index 45edd1c697..c1612b7231 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java @@ -2808,6 +2808,15 @@ public class UIText extends NLS { public static String CreateBranchWizard_NewBranchTitle; /** */ + public static String CreateBranchBulkDialog_Title; + + /** */ + public static String CreateBranchBulkDialog_Description; + + /** */ + public static String CreateBranchBulkDialog_Error; + + /** */ public static String CreateRepositoryCommand_CreateButtonLabel; /** */ diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/SwitchToMenu.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/SwitchToMenu.java index 82ed542a38..f4261578de 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/SwitchToMenu.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/SwitchToMenu.java @@ -16,6 +16,7 @@ package org.eclipse.egit.ui.internal.actions; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -25,17 +26,23 @@ import java.util.Set; import java.util.TreeSet; import java.util.stream.Stream; +import org.eclipse.core.runtime.IStatus; import org.eclipse.egit.core.RepositoryUtil; +import org.eclipse.egit.core.internal.Utils; +import org.eclipse.egit.core.op.CreateLocalBranchOperation; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.internal.CommonUtils; import org.eclipse.egit.ui.internal.UIIcons; import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.branch.BranchOperationUI; +import org.eclipse.egit.ui.internal.components.BranchNameNormalizer; import org.eclipse.egit.ui.internal.dialogs.CheckoutDialog; import org.eclipse.egit.ui.internal.history.CommitSelectionDialog; import org.eclipse.egit.ui.internal.repository.CreateBranchWizard; import org.eclipse.egit.ui.internal.selection.SelectionUtils; import org.eclipse.jface.action.ContributionItem; +import org.eclipse.jface.dialogs.IInputValidator; +import org.eclipse.jface.dialogs.InputDialog; import org.eclipse.jface.resource.ResourceManager; import org.eclipse.jface.window.Window; import org.eclipse.jface.wizard.WizardDialog; @@ -46,10 +53,15 @@ import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.ReflogEntry; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.RepositoryState; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.util.StringUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.ui.handlers.IHandlerService; @@ -113,12 +125,18 @@ public class SwitchToMenu extends ContributionItem implements private void createDynamicMenu(Menu menu, final Repository[] repositories) { + boolean showCreateBranchItem = true; if (!isMultipleSelection(repositories)) { Repository repository = repositories[0]; createNewBranchMenuItem(menu, repository); - if (hasBranches(repository)) { - createSeparator(menu); - } + } else if (canBulkCreateNewBranch(repositories)) { + createBulkNewBranchMenuItem(menu, repositories); + } else { + showCreateBranchItem = false; + } + if (showCreateBranchItem + && Arrays.stream(repositories).anyMatch(this::hasBranches)) { + createSeparator(menu); } int itemCount = createMostActiveBranchesMenuItems(menu, repositories); @@ -138,6 +156,99 @@ public class SwitchToMenu extends ContributionItem implements } } + private boolean canBulkCreateNewBranch(Repository[] repositories) { + for (Repository repo : repositories) { + if (!hasBranches(repo)) { + return false; + } + if (repo.isBare()) { + return false; + } + if (repo.getRepositoryState() != RepositoryState.SAFE) { + return false; + } + } + return true; + } + + private void createBulkNewBranchMenuItem(Menu menu, + final Repository[] repositories) { + MenuItem newBranch = getNewBranchMenuItem(menu); + newBranch.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + InputDialog dialog = new InputDialog(e.display.getActiveShell(), + UIText.CreateBranchBulkDialog_Title, + UIText.CreateBranchBulkDialog_Description, "", //$NON-NLS-1$ + new IInputValidator() { + @Override + public String isValid(String newBranchName) { + return validateNewBulkBranchName(newBranchName, + repositories); + } + }) { + + @Override + protected Control createDialogArea(Composite parent) { + Control result = super.createDialogArea(parent); + BranchNameNormalizer normalizer = new BranchNameNormalizer( + getText()); + normalizer.setVisible(false); + return result; + } + }; + if (dialog.open() == Window.OK) { + String name = dialog.getValue(); + try { + for (Repository repository : repositories) { + Ref headRef = repository.exactRef(Constants.HEAD); + if (headRef != null) { + ObjectId headId = headRef.getLeaf() + .getObjectId(); + RevCommit head = repository.parseCommit(headId); + CreateLocalBranchOperation op = new CreateLocalBranchOperation( + repository, name, head); + op.execute(null); + } + } + BranchOperationUI.checkout(repositories, name).start(); + } catch (Exception exception) { + Activator.handleError( + UIText.CreateBranchBulkDialog_Error, exception, + true); + } + } + } + }); + } + + private MenuItem getNewBranchMenuItem(Menu parentMenu) { + MenuItem newBranch = new MenuItem(parentMenu, SWT.PUSH); + newBranch.setText(UIText.SwitchToMenu_NewBranchMenuLabel); + newBranch.setImage(newBranchImage); + return newBranch; + } + + private String validateNewBulkBranchName(String newBranchName, + Repository[] repositories) { + if (StringUtils.isEmptyOrNull(newBranchName) + || newBranchName.trim().isEmpty()) { + return UIText.CreateBranchPage_ChooseNameMessage; + } + for (Repository repo : repositories) { + IStatus status = Utils.validateNewRefName(newBranchName, repo, + Constants.R_HEADS, true); + if (status.getException() != null) { + Activator.handleStatus(status, false); + } + if (!status.isOK()) { + return Activator.getDefault().getRepositoryUtil() + .getRepositoryName(repo) + ": " + status.getMessage(); //$NON-NLS-1$ + } + } + return null; + } + private boolean hasBranches(Repository repository) { try { return !repository.getRefDatabase() @@ -150,9 +261,7 @@ public class SwitchToMenu extends ContributionItem implements } private void createNewBranchMenuItem(Menu menu, Repository repository) { - MenuItem newBranch = new MenuItem(menu, SWT.PUSH); - newBranch.setText(UIText.SwitchToMenu_NewBranchMenuLabel); - newBranch.setImage(newBranchImage); + MenuItem newBranch = getNewBranchMenuItem(menu); newBranch.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties index badc3ca884..872cbe05cd 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties @@ -944,6 +944,9 @@ CreateBranchPage_SourceTooltip=The new branch will start at this point CreateBranchPage_Title=Create a new branch in repository {0} CreateBranchWizard_CreationFailed=Branch could not be created CreateBranchWizard_NewBranchTitle=Create Branch +CreateBranchBulkDialog_Title=Create Branch in Multiple Repositories +CreateBranchBulkDialog_Description=Enter the name of a new branch to be created from HEAD in all selected repositories: +CreateBranchBulkDialog_Error=Error during bulk branch creation CreateRepositoryCommand_CreateButtonLabel=&Create CreateRepositoryPage_BareCheckbox=&Create as bare repository CreateRepositoryPage_BrowseButton=&Browse... |