diff options
author | Robin Stocker | 2013-11-22 13:25:27 +0000 |
---|---|---|
committer | Matthias Sohn | 2013-12-01 00:44:14 +0000 |
commit | 4db03b082f5cb7884ae4710e763cef8f5845e1fb (patch) | |
tree | be690d73a3e3d584672b7b8e84bda4bfd40823d6 | |
parent | 19014e0db95aee64b6267fbfce8a9ea2bff116c1 (diff) | |
download | egit-4db03b082f5cb7884ae4710e763cef8f5845e1fb.tar.gz egit-4db03b082f5cb7884ae4710e763cef8f5845e1fb.tar.xz egit-4db03b082f5cb7884ae4710e763cef8f5845e1fb.zip |
Push Tags wizard
Can be started with one or more selected tags from the repositories
view. It's also available from the team menu and the context menu of a
repository.
In the "Create Tag" dialog, there is an additional button which can be
used to create the tag and then start the push wizard for it.
Bug: 341076
Change-Id: Idbc4b6e241c37548ffa2e9697697ad3965de08e7
Signed-off-by: Robin Stocker <robin@nibor.org>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
19 files changed, 930 insertions, 69 deletions
diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/push/PushTagsWizardTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/push/PushTagsWizardTest.java new file mode 100644 index 0000000000..3a0a3fac28 --- /dev/null +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/push/PushTagsWizardTest.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2013 Robin Stocker <robin@nibor.org> and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.egit.ui.internal.push; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.io.File; + +import org.eclipse.egit.ui.common.LocalRepositoryTestCase; +import org.eclipse.egit.ui.test.TestUtil; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for "Push Tags..." wizard. + */ +public class PushTagsWizardTest extends LocalRepositoryTestCase { + + private Repository repository; + private Repository remoteRepository; + + @Before + public void createRepositories() throws Exception { + File repositoryFile = createProjectAndCommitToRepository(); + File remoteRepositoryFile = createRemoteRepository(repositoryFile); + repository = lookupRepository(repositoryFile); + remoteRepository = lookupRepository(remoteRepositoryFile); + } + + @Test + public void pushTag() throws Exception { + Git git = new Git(repository); + git.tag().setName("foo").setMessage("Foo tag").call(); + + PushTagsWizardTester wizard = PushTagsWizardTester + .startWizard(selectProject()); + wizard.selectRemote("push"); + wizard.assertNextDisabled(); + wizard.checkTag("foo"); + wizard.next(); + wizard.finish(); + + assertTagPushed("foo", remoteRepository); + } + + private SWTBotTree selectProject() { + SWTBotTree projectExplorerTree = TestUtil.getExplorerTree(); + getProjectItem(projectExplorerTree, PROJ1).select(); + return projectExplorerTree; + } + + private void assertTagPushed(String tagName, Repository remoteRepo) + throws Exception { + ObjectId pushed = remoteRepo.resolve(tagName); + assertNotNull("Expected '" + tagName + + "' to resolve to non-null ObjectId on remote repository", + pushed); + ObjectId local = repository.resolve(tagName); + assertEquals( + "Expected local tag to be the same as tag on remote after pushing", + local, pushed); + } +} diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/push/PushTagsWizardTester.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/push/PushTagsWizardTester.java new file mode 100644 index 0000000000..669fa83111 --- /dev/null +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/push/PushTagsWizardTester.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2013 Robin Stocker <robin@nibor.org> and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.egit.ui.internal.push; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import org.eclipse.egit.ui.JobFamilies; +import org.eclipse.egit.ui.internal.UIText; +import org.eclipse.egit.ui.test.ContextMenuHelper; +import org.eclipse.egit.ui.test.JobJoiner; +import org.eclipse.egit.ui.test.TestUtil; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; +import org.eclipse.swtbot.swt.finder.SWTBot; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotCombo; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; + +public class PushTagsWizardTester { + + private final SWTBot wizard; + + public static PushTagsWizardTester startWizard(SWTBotTree projectTree) { + TestUtil util = new TestUtil(); + String remoteMenu = util.getPluginLocalizedValue("RemoteSubMenu.label"); + String pushBranchMenu = util + .getPluginLocalizedValue("PushTagsCommand.name"); + ContextMenuHelper.clickContextMenu(projectTree, "Team", remoteMenu, + pushBranchMenu); + + return forShell(); + } + + public static PushTagsWizardTester forShell() { + SWTWorkbenchBot bot = new SWTWorkbenchBot(); + SWTBot wizard = bot.shell(UIText.PushTagsWizard_WindowTitle).bot(); + return new PushTagsWizardTester(wizard); + } + + public PushTagsWizardTester(SWTBot wizard) { + this.wizard = wizard; + } + + public void selectRemote(String remoteName) { + SWTBotCombo remoteCombo = wizard + .comboBoxWithLabel(UIText.PushTagsPage_RemoteLabel); + String[] items = remoteCombo.items(); + for (String item : items) { + if (item.startsWith(remoteName + ":")) { + remoteCombo.setSelection(item); + return; + } + } + throw new IllegalStateException("Could not select remote '" + + remoteName + "', items were: " + Arrays.toString(items)); + } + + public void assertNextDisabled() { + assertFalse("Expected Next button to be disabled", + wizard.button(IDialogConstants.NEXT_LABEL).isEnabled()); + } + + public void assertTagChecked(String tagName) { + assertTrue("Expected tag " + tagName + " to be checked.", + findTag(tagName).isChecked()); + } + + public void checkTag(String tagName) { + findTag(tagName).check(); + } + + private SWTBotTreeItem findTag(String tagName) { + SWTBotTree tree = wizard.tree(); + for (SWTBotTreeItem item : tree.getAllItems()) { + String text = item.getText(); + if (text.equals(tagName) || text.startsWith(tagName + " ")) + return item; + } + fail("Could not find item for tag name " + tagName); + return null; + } + + public void next() { + wizard.button(IDialogConstants.NEXT_LABEL).click(); + } + + public void cancel() { + wizard.button(IDialogConstants.CANCEL_LABEL).click(); + } + + public void finish() { + JobJoiner jobJoiner = JobJoiner.startListening(JobFamilies.PUSH, 60, + TimeUnit.SECONDS); + wizard.button(IDialogConstants.FINISH_LABEL).click(); + jobJoiner.join(); + } +} diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/history/HistoryViewTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/history/HistoryViewTest.java index bb91cda3b2..2553cabe4a 100644 --- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/history/HistoryViewTest.java +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/history/HistoryViewTest.java @@ -301,7 +301,7 @@ public class HistoryViewTest extends LocalRepositoryTestCase { .setText("NewTag"); dialog.bot().styledTextWithLabel(UIText.CreateTagDialog_tagMessage) .setText("New Tag message"); - dialog.bot().button(IDialogConstants.OK_LABEL).click(); + dialog.bot().button(UIText.CreateTagDialog_CreateTagButton).click(); TestUtil.joinJobs(JobFamilies.TAG); assertNotNull(repo.resolve(Constants.R_TAGS + "NewTag")); } diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/team/actions/TagActionTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/team/actions/TagActionTest.java index e72852a055..08620396a6 100644 --- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/team/actions/TagActionTest.java +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/team/actions/TagActionTest.java @@ -22,12 +22,12 @@ import org.eclipse.egit.ui.common.LocalRepositoryTestCase; import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.test.ContextMenuHelper; import org.eclipse.egit.ui.test.TestUtil; -import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.TagBuilder; import org.eclipse.jgit.util.RawParseUtils; import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotButton; import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; import org.eclipse.swtbot.swt.finder.widgets.SWTBotTable; import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree; @@ -70,22 +70,42 @@ public class TagActionTest extends LocalRepositoryTestCase { SWTBotShell tagDialog = openTagDialog(); tagDialog.bot().textWithLabel(UIText.CreateTagDialog_tagName).setText( "SomeTag"); - assertFalse("Ok should be disabled", tagDialog.bot().button( - IDialogConstants.OK_LABEL).isEnabled()); + assertFalse("Ok should be disabled", + tagDialog.bot().button(UIText.CreateTagDialog_CreateTagButton) + .isEnabled()); tagDialog.bot().button(UIText.CreateTagDialog_clearButton) .click(); tagDialog.bot().textWithLabel(UIText.CreateTagDialog_tagName).setText( "AnotherTag"); - assertFalse("Ok should be disabled", tagDialog.bot().button( - IDialogConstants.OK_LABEL).isEnabled()); + assertFalse("Ok should be disabled", + tagDialog.bot().button(UIText.CreateTagDialog_CreateTagButton) + .isEnabled()); tagDialog.bot().styledTextWithLabel(UIText.CreateTagDialog_tagMessage) .setText("Here's the message text"); - tagDialog.bot().button(IDialogConstants.OK_LABEL).click(); + tagDialog.bot().button(UIText.CreateTagDialog_CreateTagButton).click(); waitInUI(); assertTrue(lookupRepository(repositoryFile).getTags().keySet() .contains("AnotherTag")); } + @Test + public void testCreateTagAndStartPush() throws Exception { + SWTBotShell tagDialog = openTagDialog(); + SWTBotButton button = tagDialog.bot() + .button(UIText.CreateTagDialog_CreateTagAndStartPushButton); + assertFalse("'Create Tag And Start Push' should be disabled", + button.isEnabled()); + tagDialog.bot().textWithLabel(UIText.CreateTagDialog_tagName) + .setText("tag-to-push"); + tagDialog.bot().styledTextWithLabel(UIText.CreateTagDialog_tagMessage) + .setText("Tag to push"); + button.click(); + + SWTBotShell pushTagsWizard = bot + .shell(UIText.PushTagsWizard_WindowTitle); + pushTagsWizard.close(); + } + private SWTBotShell openTagDialog() throws Exception { SWTBotTree projectExplorerTree = TestUtil.getExplorerTree(); getProjectItem(projectExplorerTree, PROJ1).select(); @@ -102,30 +122,33 @@ public class TagActionTest extends LocalRepositoryTestCase { @Test public void testChangeTagMessage() throws Exception { SWTBotShell tagDialog = openTagDialog(); - assertFalse("Ok should be disabled", tagDialog.bot().button( - IDialogConstants.OK_LABEL).isEnabled()); + assertFalse("Ok should be disabled", + tagDialog.bot().button(UIText.CreateTagDialog_CreateTagButton) + .isEnabled()); tagDialog.bot().textWithLabel(UIText.CreateTagDialog_tagName).setText( "MessageChangeTag"); - assertFalse("Ok should be disabled", tagDialog.bot().button( - IDialogConstants.OK_LABEL).isEnabled()); + assertFalse("Ok should be disabled", + tagDialog.bot().button(UIText.CreateTagDialog_CreateTagButton) + .isEnabled()); tagDialog.bot().styledTextWithLabel(UIText.CreateTagDialog_tagMessage) .setText("Here's the first message"); - tagDialog.bot().button(IDialogConstants.OK_LABEL).click(); + tagDialog.bot().button(UIText.CreateTagDialog_CreateTagButton).click(); waitInUI(); assertTrue(lookupRepository(repositoryFile).getTags().keySet() .contains("MessageChangeTag")); tagDialog = openTagDialog(); tagDialog.bot().tableWithLabel(UIText.CreateTagDialog_existingTags) .getTableItem("MessageChangeTag").select(); - assertFalse("Ok should be disabled", tagDialog.bot().button( - IDialogConstants.OK_LABEL).isEnabled()); + assertFalse("Ok should be disabled", + tagDialog.bot().button(UIText.CreateTagDialog_CreateTagButton) + .isEnabled()); String oldText = tagDialog.bot().styledTextWithLabel( UIText.CreateTagDialog_tagMessage).getText(); assertEquals("Wrong message text", "Here's the first message", oldText); tagDialog.bot().checkBox(UIText.CreateTagDialog_overwriteTag).click(); tagDialog.bot().styledTextWithLabel(UIText.CreateTagDialog_tagMessage) .setText("New message"); - tagDialog.bot().button(IDialogConstants.OK_LABEL).click(); + tagDialog.bot().button(UIText.CreateTagDialog_CreateTagButton).click(); tagDialog = openTagDialog(); tagDialog.bot().tableWithLabel(UIText.CreateTagDialog_existingTags) .getTableItem("MessageChangeTag").select(); diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTagHandlingTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTagHandlingTest.java index fcda62ec55..63fe7e825a 100644 --- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTagHandlingTest.java +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTagHandlingTest.java @@ -23,6 +23,7 @@ import org.eclipse.core.runtime.jobs.Job; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.JobFamilies; import org.eclipse.egit.ui.internal.UIText; +import org.eclipse.egit.ui.internal.push.PushTagsWizardTester; import org.eclipse.egit.ui.test.ContextMenuHelper; import org.eclipse.egit.ui.test.TestUtil; import org.eclipse.jface.dialogs.IDialogConstants; @@ -172,6 +173,20 @@ public class GitRepositoriesViewTagHandlingTest extends assertEquals("Wrong content", initialContent, getTestFileContent()); } + @Test + public void testPushTagPreselectsTag() throws Exception { + createTag("tag-to-push", "Tag to push"); + SWTBotTree tree = getOrOpenView().bot().tree(); + myRepoViewUtil.getTagsItem(tree, repositoryFile) + .expand().getNode("tag-to-push").select(); + ContextMenuHelper.clickContextMenu(tree, + myUtil.getPluginLocalizedValue("RepoViewPushTag.label")); + + PushTagsWizardTester tester = PushTagsWizardTester.forShell(); + tester.assertTagChecked("tag-to-push"); + tester.cancel(); + } + private String getCommitIdOfTag(String tagName) throws Exception { return revWalk.parseTag(repository.resolve(tagName)).getObject() .getId().name(); @@ -190,7 +205,8 @@ public class GitRepositoriesViewTagHandlingTest extends createDialog.bot() .styledTextWithLabel(UIText.CreateTagDialog_tagMessage) .setText(message); - createDialog.bot().button(IDialogConstants.OK_LABEL).click(); + createDialog.bot().button(UIText.CreateTagDialog_CreateTagButton) + .click(); TestUtil.joinJobs(JobFamilies.TAG); } diff --git a/org.eclipse.egit.ui/plugin.properties b/org.eclipse.egit.ui/plugin.properties index 3ae2bc6aef..c0c29db7c7 100644 --- a/org.eclipse.egit.ui/plugin.properties +++ b/org.eclipse.egit.ui/plugin.properties @@ -238,6 +238,7 @@ IgnoreCommand.name = Ignore MergeCommand.name = Merge PushCommand.name = Push PushBranchCommand.name = Push Branch... +PushTagsCommand.name = Push Tags... ResetCommand.name2 = Reset SynchronizeCommand.name = Synchronize TagCommand.name = Tag diff --git a/org.eclipse.egit.ui/plugin.xml b/org.eclipse.egit.ui/plugin.xml index 9121cf4fa1..d38b64aa26 100644 --- a/org.eclipse.egit.ui/plugin.xml +++ b/org.eclipse.egit.ui/plugin.xml @@ -848,6 +848,11 @@ </command> <command categoryId="org.eclipse.egit.ui.commandCategory" + id="org.eclipse.egit.ui.team.PushTags" + name="%PushTagsCommand.name"> + </command> + <command + categoryId="org.eclipse.egit.ui.commandCategory" id="org.eclipse.egit.ui.team.Merge" name="%MergeCommand.name"> </command> @@ -1128,24 +1133,33 @@ class="org.eclipse.egit.ui.internal.repository.tree.command.PushCommand"> </class> <activeWhen> - <and> - <count - value="1"> - </count> - <iterate> - <or> - <instanceof - value="org.eclipse.egit.ui.internal.repository.tree.RefNode"> - </instanceof> - <instanceof - value="org.eclipse.egit.ui.internal.repository.tree.TagNode"> - </instanceof> - <instanceof - value="org.eclipse.egit.ui.internal.repository.tree.RepositoryNode"> - </instanceof> - </or> - </iterate> - </and> + <or> + <and> + <count + value="1"> + </count> + <iterate> + <or> + <instanceof + value="org.eclipse.egit.ui.internal.repository.tree.RefNode"> + </instanceof> + <instanceof + value="org.eclipse.egit.ui.internal.repository.tree.RepositoryNode"> + </instanceof> + </or> + </iterate> + </and> + <and> + <count + value="+"> + </count> + <iterate> + <instanceof + value="org.eclipse.egit.ui.internal.repository.tree.TagNode"> + </instanceof> + </iterate> + </and> + </or> </activeWhen> </handler> <handler @@ -1190,6 +1204,39 @@ </activeWhen> </handler> <handler + commandId="org.eclipse.egit.ui.team.PushTags"> + <class + class="org.eclipse.egit.ui.internal.actions.PushTagsActionHandler"> + </class> + <activeWhen> + <or> + <reference + definitionId="org.eclipse.egit.ui.gitProject"> + </reference> + <and> + <count + value="1"> + </count> + <iterate> + <instanceof + value="org.eclipse.egit.ui.internal.repository.tree.RepositoryNode"> + </instanceof> + </iterate> + </and> + <and> + <count + value="1"> + </count> + <iterate> + <instanceof + value="org.eclipse.egit.ui.internal.repository.tree.TagsNode"> + </instanceof> + </iterate> + </and> + </or> + </activeWhen> + </handler> + <handler commandId="org.eclipse.egit.ui.team.Merge"> <class class="org.eclipse.egit.ui.internal.repository.tree.command.MergeCommand"> @@ -2166,7 +2213,7 @@ checkEnabled="false"> <and> <count - value="1"> + value="+"> </count> <iterate> <instanceof @@ -2516,6 +2563,25 @@ </and> </visibleWhen> </command> + <command + commandId="org.eclipse.egit.ui.team.PushTags" + style="push"> + <visibleWhen + checkEnabled="false"> + <and> + <count + value="1"> + </count> + <iterate> + <or> + <instanceof + value="org.eclipse.egit.ui.internal.repository.tree.TagsNode"> + </instanceof> + </or> + </iterate> + </and> + </visibleWhen> + </command> </menuContribution> <menuContribution locationURI="popup:org.eclipse.egit.ui.RepositoriesView?after=remote"> @@ -3057,6 +3123,23 @@ </visibleWhen> </command> <command + commandId="org.eclipse.egit.ui.team.PushTags" + style="push"> + <visibleWhen + checkEnabled="false"> + <and> + <count + value="1"> + </count> + <iterate> + <instanceof + value="org.eclipse.egit.ui.internal.repository.tree.RepositoryNode"> + </instanceof> + </iterate> + </and> + </visibleWhen> + </command> + <command commandId="org.eclipse.egit.ui.team.Fetch" icon="icons/obj16/fetch.gif" label="%RepoViewFetch.label" @@ -3747,6 +3830,10 @@ style="push"> </command> <command + commandId="org.eclipse.egit.ui.team.PushTags" + style="push"> + </command> + <command commandId="org.eclipse.egit.ui.team.Fetch" label="%FetchAction_label" style="push"> @@ -4693,6 +4780,10 @@ icon="icons/obj16/push.gif"> </image> <image + commandId="org.eclipse.egit.ui.team.PushTags" + icon="icons/obj16/push.gif"> + </image> + <image commandId="org.eclipse.egit.ui.FetchGerritChange" icon="icons/obj16/gerrit_fetch.gif"> </image> 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 f6bb0e875a..f0226bdc38 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 @@ -2526,6 +2526,30 @@ public class UIText extends NLS { public static String PushResultTable_statusOkNewTag; /** */ + public static String PushTagsPage_ForceUpdateButton; + + /** */ + public static String PushTagsPage_PageMessage; + + /** */ + public static String PushTagsPage_PageName; + + /** */ + public static String PushTagsPage_PageTitle; + + /** */ + public static String PushTagsPage_RemoteLabel; + + /** */ + public static String PushTagsPage_TagsLabelNoneSelected; + + /** */ + public static String PushTagsPage_TagsLabelSelected; + + /** */ + public static String PushTagsWizard_WindowTitle; + + /** */ public static String PushToGerritPage_BranchLabel; /** */ @@ -3789,6 +3813,15 @@ public class UIText extends NLS { public static String CreateTagDialog_clearButtonTooltip; /** */ + public static String CreateTagDialog_CreateTagAndStartPushButton; + + /** */ + public static String CreateTagDialog_CreateTagAndStartPushToolTip; + + /** */ + public static String CreateTagDialog_CreateTagButton; + + /** */ public static String CreateTagDialog_CreateTagOnCommitTitle; /** */ diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushTagsActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushTagsActionHandler.java new file mode 100644 index 0000000000..f5c17c67cb --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushTagsActionHandler.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2013 Robin Stocker <robin@nibor.org> and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.egit.ui.internal.actions; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.egit.ui.internal.push.PushTagsWizard; +import org.eclipse.jgit.lib.Repository; + +/** + * "Push Tags..." action for repository + */ +public class PushTagsActionHandler extends RepositoryActionHandler { + public Object execute(ExecutionEvent event) throws ExecutionException { + Repository repository = getRepository(true, event); + + PushTagsWizard.openWizardDialog(repository); + + return null; + } + + @Override + public boolean isEnabled() { + return getRepository() != null; + } +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/TagActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/TagActionHandler.java index 2456666b06..3ec5bdf1f3 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/TagActionHandler.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/TagActionHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org> + * Copyright (C) 2010, 2013 Dariusz Luksza <dariusz@luksza.org> and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -16,13 +16,16 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.egit.core.op.TagOperation; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.JobFamilies; import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.decorators.GitLightweightDecorator; import org.eclipse.egit.ui.internal.dialogs.CreateTagDialog; +import org.eclipse.egit.ui.internal.push.PushTagsWizard; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jgit.lib.Constants; @@ -71,7 +74,7 @@ public class TagActionHandler extends RepositoryActionHandler { final TagBuilder tag = new TagBuilder(); PersonIdent personIdent = new PersonIdent(repo); - String tagName = dialog.getTagName(); + final String tagName = dialog.getTagName(); tag.setTag(tagName); tag.setTagger(personIdent); @@ -112,6 +115,16 @@ public class TagActionHandler extends RepositoryActionHandler { } }; + if (dialog.shouldStartPushWizard()) { + tagJob.addJobChangeListener(new JobChangeAdapter() { + @Override + public void done(IJobChangeEvent jobChangeEvent) { + if (jobChangeEvent.getResult().isOK()) + PushTagsWizard.openWizardDialog(repo, tagName); + } + }); + } + tagJob.setUser(true); tagJob.schedule(); return null; diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/command/CreateTagHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/command/CreateTagHandler.java index 838259c949..9b0959a993 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/command/CreateTagHandler.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/command/CreateTagHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 GitHub Inc. + * Copyright (c) 2011, 2013 GitHub Inc and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -19,8 +19,10 @@ import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.egit.core.op.TagOperation; import org.eclipse.egit.ui.internal.commit.RepositoryCommit; import org.eclipse.egit.ui.internal.dialogs.CreateTagDialog; +import org.eclipse.egit.ui.internal.push.PushTagsWizard; import org.eclipse.jface.window.Window; import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.TagBuilder; import org.eclipse.ui.handlers.HandlerUtil; @@ -39,15 +41,16 @@ public class CreateTagHandler extends CommitCommandHandler { if (commits.size() == 1) { RepositoryCommit commit = commits.get(0); + Repository repository = commit.getRepository(); CreateTagDialog dialog = new CreateTagDialog( HandlerUtil.getActiveShellChecked(event), commit - .getRevCommit().getId(), commit.getRepository()); + .getRevCommit().getId(), repository); if (dialog.open() != Window.OK) return null; final TagBuilder tag = new TagBuilder(); - PersonIdent personIdent = new PersonIdent(commit.getRepository()); + PersonIdent personIdent = new PersonIdent(repository); String tagName = dialog.getTagName(); tag.setTag(tagName); @@ -56,12 +59,15 @@ public class CreateTagHandler extends CommitCommandHandler { tag.setObjectId(commit.getRevCommit()); try { - new TagOperation(commit.getRepository(), tag, + new TagOperation(repository, tag, dialog.shouldOverWriteTag()) .execute(new NullProgressMonitor()); } catch (CoreException e) { throw new ExecutionException(e.getMessage(), e); } + + if (dialog.shouldStartPushWizard()) + PushTagsWizard.openWizardDialog(repository, tagName); } return null; } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CreateTagDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CreateTagDialog.java index e9b13441a0..1be7e78d69 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CreateTagDialog.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CreateTagDialog.java @@ -89,9 +89,14 @@ public class CreateTagDialog extends TitleAreaDialog { private static final int MAX_COMMIT_COUNT = 1000; /** - * Button id for a "Clear" button (value 22). + * Button id for a "Clear" button. */ - public static final int CLEAR_ID = 22; + private static final int CLEAR_ID = 22; + + /** + * Button id for "Create Tag and Start Push..." button + */ + private static final int CREATE_AND_START_PUSH_ID = 23; private String tagName; @@ -99,6 +104,8 @@ public class CreateTagDialog extends TitleAreaDialog { private ObjectId tagCommit; + private boolean shouldStartPushWizard = false; + private boolean overwriteTag; /** Tag object in case an existing annotated tag was entered */ @@ -232,6 +239,14 @@ public class CreateTagDialog extends TitleAreaDialog { return overwriteTag; } + /** + * @return true if the user wants to start the push wizard after creating + * the tag, false otherwise + */ + public boolean shouldStartPushWizard() { + return shouldStartPushWizard; + } + @Override protected void configureShell(Shell newShell) { super.configureShell(newShell); @@ -265,8 +280,16 @@ public class CreateTagDialog extends TitleAreaDialog { margin.setLayoutData(GridDataFactory.fillDefaults().grab(true, false) .create()); + Button createTagAndStartPushButton = createButton(parent, + CREATE_AND_START_PUSH_ID, UIText.CreateTagDialog_CreateTagAndStartPushButton, false); + createTagAndStartPushButton + .setToolTipText(UIText.CreateTagDialog_CreateTagAndStartPushToolTip); + setButtonLayoutData(createTagAndStartPushButton); + super.createButtonsForButtonBar(parent); + getButton(OK).setText(UIText.CreateTagDialog_CreateTagButton); + validateInput(); } @@ -338,8 +361,7 @@ public class CreateTagDialog extends TitleAreaDialog { @Override protected void buttonPressed(int buttonId) { - switch (buttonId) { - case CLEAR_ID: + if (buttonId == CLEAR_ID) { tagNameText.setText(""); //$NON-NLS-1$ tagMessageText.setText(""); //$NON-NLS-1$ if (commitCombo != null) { @@ -348,16 +370,17 @@ public class CreateTagDialog extends TitleAreaDialog { tagMessageText.getTextWidget().setEditable(true); overwriteButton.setEnabled(false); overwriteButton.setSelection(false); - break; - case IDialogConstants.OK_ID: + } else if (buttonId == IDialogConstants.OK_ID + || buttonId == CREATE_AND_START_PUSH_ID) { + shouldStartPushWizard = (buttonId == CREATE_AND_START_PUSH_ID); // read and store data from widgets tagName = tagNameText.getText(); if (commitCombo != null) tagCommit = commitCombo.getValue(); tagMessage = tagMessageText.getCommitMessage(); overwriteTag = overwriteButton.getSelection(); - //$FALL-THROUGH$ continue propagating OK button action - default: + okPressed(); + } else { super.buttonPressed(buttonId); } } @@ -581,7 +604,12 @@ public class CreateTagDialog extends TitleAreaDialog { boolean shouldOverwriteTag = (overwriteButton.getSelection() && Repository .isValidRefName(Constants.R_TAGS + tagNameText.getText())); - button.setEnabled(containsTagNameAndMessage || shouldOverwriteTag); + boolean enabled = containsTagNameAndMessage || shouldOverwriteTag; + button.setEnabled(enabled); + + Button createTagAndStartPush = getButton(CREATE_AND_START_PUSH_ID); + if (createTagAndStartPush != null) + createTagAndStartPush.setEnabled(enabled); } boolean existingTagSelected = existingTag != null; diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/command/CreateTagOnCommitHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/command/CreateTagOnCommitHandler.java index a466257eeb..ed051586dd 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/command/CreateTagOnCommitHandler.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/command/CreateTagOnCommitHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com> + * Copyright (C) 2010, 2013 Mathias Kinzler <mathias.kinzler@sap.com> and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -15,6 +15,7 @@ import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.egit.core.op.TagOperation; import org.eclipse.egit.ui.internal.dialogs.CreateTagDialog; import org.eclipse.egit.ui.internal.history.GitHistoryPage; +import org.eclipse.egit.ui.internal.push.PushTagsWizard; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.jgit.lib.PersonIdent; @@ -53,6 +54,10 @@ public class CreateTagOnCommitHandler extends AbstractHistoryCommandHandler { } catch (CoreException e) { throw new ExecutionException(e.getMessage(), e); } + + if (dialog.shouldStartPushWizard()) + PushTagsWizard.openWizardDialog(repo, tagName); + return null; } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushOperationUI.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushOperationUI.java index 654a036b55..9a9a94b858 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushOperationUI.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushOperationUI.java @@ -60,6 +60,10 @@ public class PushOperationUI { private final String remoteName; + private PushOperationResult expectedResult; + + private boolean showConfigureButton = true; + /** * @param repository * @param remoteName @@ -124,6 +128,26 @@ public class PushOperationUI { } /** + * Set the expected result. If this is set, the result dialog in {@link #start()} will only be + * shown when the result is different from the expected result. + * + * @param expectedResult + */ + public void setExpectedResult(PushOperationResult expectedResult) { + this.expectedResult = expectedResult; + } + + /** + * Set whether the "Configure..." button should be shown in the result + * dialog of {@link #start()}. + * + * @param showConfigureButton + */ + public void setShowConfigureButton(boolean showConfigureButton) { + this.showConfigureButton = showConfigureButton; + } + + /** * Executes this directly, without showing a confirmation dialog * * @param monitor @@ -219,12 +243,15 @@ public class PushOperationUI { job.addJobChangeListener(new JobChangeAdapter() { @Override public void done(IJobChangeEvent event) { - if (event.getResult().isOK()) - PushResultDialog.show(repository, op.getOperationResult(), - destinationString); - else - Activator.handleError(event.getResult().getMessage(), event - .getResult().getException(), true); + PushOperationResult result = op.getOperationResult(); + if (expectedResult == null || !expectedResult.equals(result)) { + if (event.getResult().isOK()) + PushResultDialog.show(repository, result, + destinationString, showConfigureButton); + else + Activator.handleError(event.getResult().getMessage(), + event.getResult().getException(), true); + } } }); } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushResultDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushResultDialog.java index 5d43e333e9..f67e35036b 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushResultDialog.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushResultDialog.java @@ -43,9 +43,13 @@ class PushResultDialog extends TitleAreaDialog { * @param repository * @param result * @param sourceString + * @param showConfigureButton + * whether to show the "Configure..." button in the result dialog + * or not */ public static void show(final Repository repository, - final PushOperationResult result, final String sourceString) { + final PushOperationResult result, final String sourceString, + final boolean showConfigureButton) { PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { public void run() { PlatformUI.getWorkbench().getDisplay().asyncExec( @@ -53,8 +57,10 @@ class PushResultDialog extends TitleAreaDialog { public void run() { Shell shell = PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getShell(); - new PushResultDialog(shell, repository, result, - sourceString).open(); + PushResultDialog dialog = new PushResultDialog( + shell, repository, result, sourceString); + dialog.showConfigureButton(showConfigureButton); + dialog.open(); } }); } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushTagsPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushTagsPage.java new file mode 100644 index 0000000000..d51bb0bd8a --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushTagsPage.java @@ -0,0 +1,215 @@ +/******************************************************************************* + * Copyright (c) 2013 Robin Stocker <robin@nibor.org> and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.egit.ui.internal.push; + +import java.net.URISyntaxException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.egit.ui.internal.CachedCheckboxTreeViewer; +import org.eclipse.egit.ui.internal.CommonUtils; +import org.eclipse.egit.ui.internal.FilteredCheckboxTree; +import org.eclipse.egit.ui.internal.UIText; +import org.eclipse.egit.ui.internal.components.RemoteSelectionCombo; +import org.eclipse.egit.ui.internal.components.RemoteSelectionCombo.SelectionType; +import org.eclipse.egit.ui.internal.repository.RepositoriesViewContentProvider; +import org.eclipse.egit.ui.internal.repository.RepositoriesViewStyledCellLabelProvider; +import org.eclipse.egit.ui.internal.repository.tree.TagNode; +import org.eclipse.egit.ui.internal.repository.tree.TagsNode; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.layout.LayoutConstants; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.RemoteConfig; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; + +/** + * Tag to select a remote and one or more tags to push. + */ +public class PushTagsPage extends WizardPage { + + private final Repository repository; + + private final Set<String> tagRefNamesToSelect = new HashSet<String>(); + + private RemoteConfig selectedRemoteConfig = null; + + private List<TagNode> selectedTags = new ArrayList<TagNode>(); + + private boolean forceUpdateSelected = false; + + private Label tagsLabel; + + /** + * @param repository + * @param tagNamesToSelect + */ + public PushTagsPage(Repository repository, + Collection<String> tagNamesToSelect) { + super(UIText.PushTagsPage_PageName); + setTitle(UIText.PushTagsPage_PageTitle); + setMessage(UIText.PushTagsPage_PageMessage); + + this.repository = repository; + for (String tagName : tagNamesToSelect) { + if (tagName.startsWith(Constants.R_TAGS)) + tagRefNamesToSelect.add(tagName); + else + tagRefNamesToSelect.add(Constants.R_TAGS + tagName); + } + } + + public void createControl(Composite parent) { + Composite main = new Composite(parent, SWT.NONE); + main.setLayout(GridLayoutFactory.swtDefaults() + .spacing(LayoutConstants.getSpacing()).numColumns(2).create()); + + Label remoteLabel = new Label(main, SWT.NONE); + remoteLabel.setText(UIText.PushTagsPage_RemoteLabel); + + RemoteSelectionCombo remoteSelectionCombo = new RemoteSelectionCombo( + main, SWT.NONE, SelectionType.PUSH); + remoteSelectionCombo.setLayoutData(GridDataFactory.fillDefaults() + .grab(true, false).create()); + selectedRemoteConfig = remoteSelectionCombo + .setItems(getRemoteConfigs()); + remoteSelectionCombo + .addRemoteSelectionListener(new RemoteSelectionCombo.IRemoteSelectionListener() { + public void remoteSelected(RemoteConfig remoteConfig) { + selectedRemoteConfig = remoteConfig; + } + }); + + tagsLabel = new Label(main, SWT.NONE); + tagsLabel.setText(UIText.PushTagsPage_TagsLabelNoneSelected); + tagsLabel.setLayoutData(GridDataFactory.fillDefaults() + .grab(true, false).span(2, 1).create()); + + FilteredCheckboxTree tree = new FilteredCheckboxTree(main, null, + SWT.BORDER); + tree.setLayoutData(GridDataFactory.fillDefaults().grab(true, true) + .span(2, 1).hint(400, 300).create()); + + final Button forceUpdateButton = new Button(main, SWT.CHECK); + forceUpdateButton + .setText(UIText.PushTagsPage_ForceUpdateButton); + forceUpdateButton.setSelection(false); + forceUpdateButton.setLayoutData(GridDataFactory.fillDefaults() + .grab(true, false).span(2, 1).create()); + forceUpdateButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + forceUpdateSelected = forceUpdateButton.getSelection(); + } + }); + + final CachedCheckboxTreeViewer treeViewer = tree + .getCheckboxTreeViewer(); + final TagsNode tagsNode = new TagsNode(null, repository); + RepositoriesViewContentProvider contentProvider = new RepositoriesViewContentProvider() { + @Override + public Object[] getElements(Object inputElement) { + return getChildren(tagsNode); + } + }; + treeViewer.setContentProvider(contentProvider); + treeViewer + .setLabelProvider(new RepositoriesViewStyledCellLabelProvider()); + treeViewer.setComparator(new ViewerComparator( + CommonUtils.STRING_ASCENDING_COMPARATOR)); + treeViewer.setInput(tagsNode); + + final Object[] tagNodes = contentProvider.getElements(tagsNode); + initiallySelectTags(tagNodes, treeViewer); + + treeViewer.addCheckStateListener(new ICheckStateListener() { + public void checkStateChanged(CheckStateChangedEvent event) { + setSelectedTags(treeViewer.getCheckedElements()); + } + }); + + setControl(main); + } + + @Override + public boolean isPageComplete() { + return selectedRemoteConfig != null && !selectedTags.isEmpty(); + } + + RemoteConfig getSelectedRemoteConfig() { + return selectedRemoteConfig; + } + + List<TagNode> getSelectedTags() { + return selectedTags; + } + + boolean isForceUpdateSelected() { + return forceUpdateSelected; + } + + private void initiallySelectTags(Object[] tagNodes, + CheckboxTreeViewer viewer) { + List<TagNode> checkedTags = new ArrayList<TagNode>(); + for (Object node : tagNodes) { + if (node instanceof TagNode) { + TagNode tagNode = (TagNode) node; + Ref ref = tagNode.getObject(); + if (tagRefNamesToSelect.contains(ref.getName())) + checkedTags.add(tagNode); + } + } + + TagNode[] checkedTagsArray = checkedTags + .toArray(new TagNode[checkedTags.size()]); + viewer.setCheckedElements(checkedTagsArray); + viewer.setSelection(StructuredSelection.EMPTY); + if (checkedTagsArray.length > 0) + viewer.reveal(checkedTagsArray[0]); + setSelectedTags(checkedTagsArray); + } + + private void setSelectedTags(Object[] tags) { + selectedTags.clear(); + for (Object tag : tags) { + if (tag instanceof TagNode) + selectedTags.add((TagNode) tag); + } + int number = selectedTags.size(); + if (number == 0) + tagsLabel.setText(UIText.PushTagsPage_TagsLabelNoneSelected); + else + tagsLabel.setText(MessageFormat.format(UIText.PushTagsPage_TagsLabelSelected, + Integer.valueOf(selectedTags.size()))); + setPageComplete(isPageComplete()); + } + + private List<RemoteConfig> getRemoteConfigs() { + try { + return RemoteConfig.getAllRemoteConfigs(repository.getConfig()); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushTagsWizard.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushTagsWizard.java new file mode 100644 index 0000000000..a93a352fbe --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushTagsWizard.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright (c) 2013 Robin Stocker <robin@nibor.org> and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.egit.ui.internal.push; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.eclipse.egit.core.op.PushOperationResult; +import org.eclipse.egit.core.op.PushOperationSpecification; +import org.eclipse.egit.ui.internal.UIText; +import org.eclipse.egit.ui.internal.components.RepositorySelection; +import org.eclipse.egit.ui.internal.credentials.EGitCredentialsProvider; +import org.eclipse.egit.ui.internal.repository.tree.TagNode; +import org.eclipse.jface.wizard.IWizardPage; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.RefSpec; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.PlatformUI; + +/** + * Wizard for pushing one or more tags to a remote. + */ +public class PushTagsWizard extends Wizard { + + private final Repository repository; + + private final PushTagsPage pushTagsPage; + + private final ConfirmationPage confirmationPage; + + /** + * Creates a wizard with the passed parameters and opens a dialog with it in + * the active workbench window shell. + * + * @param repository + * @param tagNames + */ + public static void openWizardDialog(final Repository repository, + final String... tagNames) { + PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { + public void run() { + Shell shell = PlatformUI.getWorkbench() + .getActiveWorkbenchWindow().getShell(); + PushTagsWizard wizard = new PushTagsWizard(repository, Arrays + .asList(tagNames)); + WizardDialog dialog = new WizardDialog(shell, wizard); + dialog.setHelpAvailable(false); + dialog.open(); + } + }); + } + + /** + * @param repository + * @param tagNamesToSelect + */ + public PushTagsWizard(Repository repository, + Collection<String> tagNamesToSelect) { + this.repository = repository; + pushTagsPage = new PushTagsPage(repository, tagNamesToSelect); + confirmationPage = new ConfirmationPage(repository) { + @Override + public void setVisible(boolean visible) { + if (visible) + setSelection(getRepositorySelection(), getRefSpecs()); + super.setVisible(visible); + } + }; + } + + @Override + public String getWindowTitle() { + return UIText.PushTagsWizard_WindowTitle; + } + + @Override + public void addPages() { + addPage(pushTagsPage); + addPage(confirmationPage); + } + + @Override + public IWizardPage getNextPage(IWizardPage page) { + if (page == pushTagsPage) { + return confirmationPage; + } + return null; + } + + @Override + public boolean canFinish() { + return getContainer().getCurrentPage() == confirmationPage; + } + + @Override + public boolean performFinish() { + try { + startPush(); + return true; + } catch (IOException e) { + confirmationPage.setErrorMessage(e.getMessage()); + return false; + } + } + + private RepositorySelection getRepositorySelection() { + return new RepositorySelection(null, + pushTagsPage.getSelectedRemoteConfig()); + } + + private List<RefSpec> getRefSpecs() { + List<RefSpec> specs = new ArrayList<RefSpec>(); + String prefix; + if (pushTagsPage.isForceUpdateSelected()) + prefix = "+"; //$NON-NLS-1$ + else + prefix = ""; //$NON-NLS-1$ + for (TagNode tag : pushTagsPage.getSelectedTags()) { + String refName = tag.getObject().getName(); + RefSpec spec = new RefSpec(prefix + refName); + specs.add(spec); + } + return specs; + } + + private void startPush() throws IOException { + PushOperationResult result = confirmationPage.getConfirmedResult(); + PushOperationSpecification pushSpec = result + .deriveSpecification(confirmationPage + .isRequireUnchangedSelected()); + + PushOperationUI pushOperationUI = new PushOperationUI(repository, + pushSpec, false); + pushOperationUI.setCredentialsProvider(new EGitCredentialsProvider()); + pushOperationUI.setShowConfigureButton(false); + if (confirmationPage.isShowOnlyIfChangedSelected()) + pushOperationUI.setExpectedResult(confirmationPage + .getConfirmedResult()); + pushOperationUI.start(); + } +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushCommand.java index 00f544c15a..5a89f20511 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushCommand.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushCommand.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010 SAP AG. + * Copyright (c) 2010, 2013 SAP AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -11,26 +11,30 @@ package org.eclipse.egit.ui.internal.repository.tree.command; import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.egit.ui.Activator; -import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.push.PushBranchWizard; +import org.eclipse.egit.ui.internal.push.PushTagsWizard; import org.eclipse.egit.ui.internal.push.PushWizard; -import org.eclipse.egit.ui.internal.push.SimplePushRefWizard; -import org.eclipse.egit.ui.internal.repository.tree.RepositoryNode; import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode; +import org.eclipse.egit.ui.internal.repository.tree.TagNode; import org.eclipse.jface.wizard.IWizard; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; /** * Implements "Push" from a Repository */ -public class PushCommand extends RepositoriesViewCommandHandler<RepositoryNode> { +public class PushCommand extends + RepositoriesViewCommandHandler<RepositoryTreeNode> { public Object execute(ExecutionEvent event) throws ExecutionException { - RepositoryTreeNode node = getSelectedNodes(event).get(0); + List<RepositoryTreeNode> nodes = getSelectedNodes(event); + RepositoryTreeNode node = nodes.get(0); IWizard pushWiz = null; @@ -41,8 +45,7 @@ public class PushCommand extends RepositoriesViewCommandHandler<RepositoryNode> (Ref) node.getObject()); break; case TAG: - pushWiz = new SimplePushRefWizard(node.getRepository(), - (Ref) node.getObject(), UIText.PushCommand_pushTagTitle); + pushWiz = createPushTagsWizard(nodes); break; case REPO: pushWiz = new PushWizard(node.getRepository()); @@ -52,17 +55,38 @@ public class PushCommand extends RepositoriesViewCommandHandler<RepositoryNode> } } catch (URISyntaxException e1) { Activator.handleError(e1.getMessage(), e1, true); + return null; } WizardDialog dlg = new WizardDialog(getShell(event), pushWiz); - dlg.setHelpAvailable(true); + dlg.setHelpAvailable(pushWiz.isHelpAvailable()); dlg.open(); return null; } + private PushTagsWizard createPushTagsWizard(List<RepositoryTreeNode> nodes) { + List<String> tagNames = new ArrayList<String>(); + for (RepositoryTreeNode node : nodes) { + if (node instanceof TagNode) { + TagNode tagNode = (TagNode) node; + tagNames.add(tagNode.getObject().getName()); + } + } + Repository repository = nodes.get(0).getRepository(); + return new PushTagsWizard(repository, tagNames); + } + @Override public boolean isEnabled() { + List<RepositoryTreeNode> nodes = getSelectedNodes(); + if (nodes.isEmpty()) + return false; + Repository repository = nodes.get(0).getRepository(); + for (RepositoryTreeNode node : nodes) { + if (repository != node.getRepository()) + return false; + } return selectedRepositoryHasHead(); } } 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 1dbcb6ed23..4bc6561f20 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 @@ -837,6 +837,14 @@ PushResultTable_statusUpToDate=[up to date] PushResultTable_statusOkDeleted=[deleted] PushResultTable_statusOkNewBranch=[new branch] PushResultTable_statusOkNewTag=[new tag] +PushTagsPage_ForceUpdateButton=Force overwrite of tags when they already exist on remote +PushTagsPage_PageMessage=Select a remote and the tags to push. The next page will show a confirmation. +PushTagsPage_PageName=Push Tags +PushTagsPage_PageTitle=Select Tags +PushTagsPage_RemoteLabel=Remote: +PushTagsPage_TagsLabelNoneSelected=Tags: +PushTagsPage_TagsLabelSelected=Tags ({0} selected): +PushTagsWizard_WindowTitle=Push Tags PushToGerritPage_BranchLabel=Gerrit &Branch: PushToGerritPage_ContentProposalHoverText=Press {0} to see a filtered list of branch names PushToGerritPage_Message=Select a Gerrit URI and branch name @@ -1316,6 +1324,9 @@ CreateTagDialog_advancedMessage=Choose commit that should be associated with thi CreateTagDialog_tagNameToolTip=Start typing tag name to filter list of existing tags. CreateTagDialog_clearButton=C&lear CreateTagDialog_clearButtonTooltip=Clear all dialog fields. +CreateTagDialog_CreateTagAndStartPushButton=Create Tag and Start &Push... +CreateTagDialog_CreateTagAndStartPushToolTip=Create the tag and then start the wizard to push it to a remote. +CreateTagDialog_CreateTagButton=Create &Tag CreateTagDialog_CreateTagOnCommitTitle=Create a New Tag on Commit {0} CreateTagDialog_ExceptionRetrievingTagsMessage=Exception while retrieving existing tags CreateTagDialog_GetTagJobName=Get existing tags for the Create Tag Dialog |