| author | akozak | 2011-11-24 02:07:53 (EST) |
|---|---|---|
| committer | Winston Prakash | 2011-12-01 20:47:22 (EST) |
| commit | 3e8ad3333515300e3b17d0c4756b97018362c8c9 (patch) (side-by-side diff) | |
| tree | 3a38f3b61d6dae44625e9c83186e2253beab89a3 | |
| parent | da4ded42c6a6eba2990d49bcf177216f6d12991b (diff) | |
| download | org.eclipse.hudson.core-3e8ad3333515300e3b17d0c4756b97018362c8c9.zip org.eclipse.hudson.core-3e8ad3333515300e3b17d0c4756b97018362c8c9.tar.gz org.eclipse.hudson.core-3e8ad3333515300e3b17d0c4756b97018362c8c9.tar.bz2 | |
Implement unit-tests for link/unlink cascading projects. Improve deleteConfirmation dialog. Doesn't allow to delete project with cascading children
Signed-off-by: Winston Prakash <winston.prakash@gmail.com>
7 files changed, 154 insertions, 22 deletions
diff --git a/hudson-core/src/main/java/hudson/Functions.java b/hudson-core/src/main/java/hudson/Functions.java index 50fbfbf..e0ed83c 100644 --- a/hudson-core/src/main/java/hudson/Functions.java +++ b/hudson-core/src/main/java/hudson/Functions.java @@ -1376,14 +1376,17 @@ public class Functions { * * @param cascadingProject cascading project to start from. * @param projectToUnlink project that should be unlinked. + * @return true if project was unlinked, false - if cascadingProject or projectToUnlink is Null */ - public static void unlinkCascadingProject(Job cascadingProject, String projectToUnlink) { + public static boolean unlinkProjectFromCascadingParents(Job cascadingProject, String projectToUnlink) { if (null != cascadingProject && null != projectToUnlink) { cascadingProject.removeCascadingChild(projectToUnlink); if (cascadingProject.hasCascadingProject()) { - unlinkCascadingProject(cascadingProject.getCascadingProject(), projectToUnlink); + unlinkProjectFromCascadingParents(cascadingProject.getCascadingProject(), projectToUnlink); } + return true; } + return false; } /** @@ -1393,7 +1396,6 @@ public class Functions { * @param cascadingProject cascadingProject. * @param childProjectName the name of child project name. */ - @SuppressWarnings("unchecked") public static void linkCascadingProjectsToChild(Job cascadingProject, String childProjectName){ if(cascadingProject != null){ cascadingProject.addCascadingChild(childProjectName); diff --git a/hudson-core/src/main/java/hudson/model/Job.java b/hudson-core/src/main/java/hudson/model/Job.java index 9d256a5..a2aa3da 100644 --- a/hudson-core/src/main/java/hudson/model/Job.java +++ b/hudson-core/src/main/java/hudson/model/Job.java @@ -328,6 +328,7 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R * * @return list of cascading children project names. */ + @Exported public Set<String> getCascadingChildrenNames() { return cascadingChildrenNames; } @@ -506,6 +507,7 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R // should we block until the build is cancelled? } } + //TODO delete cascading project super.performDelete(); } @@ -1505,6 +1507,7 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R if (StringUtils.isBlank(cascadingProjectName)) { clearCascadingProject(); } else if (!StringUtils.equalsIgnoreCase(this.cascadingProjectName, cascadingProjectName)) { + Functions.unlinkProjectFromCascadingParents(cascadingProject, name); this.cascadingProjectName = cascadingProjectName; this.cascadingProject = (JobT) Functions.getItemByName(Hudson.getInstance().getAllItems(this.getClass()), cascadingProjectName); @@ -1546,7 +1549,7 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R * Remove cascading project data and mark all project properties as non-overridden */ private void clearCascadingProject() { - Functions.unlinkCascadingProject(cascadingProject, name); + Functions.unlinkProjectFromCascadingParents(cascadingProject, name); this.cascadingProject = null; this.cascadingProjectName = null; for (IProjectProperty property : jobProperties.values()) { diff --git a/hudson-core/src/main/resources/hudson/model/AbstractProject/delete.jelly b/hudson-core/src/main/resources/hudson/model/AbstractProject/delete.jelly new file mode 100644 index 0000000..3bf709a --- a/dev/null +++ b/hudson-core/src/main/resources/hudson/model/AbstractProject/delete.jelly @@ -0,0 +1,38 @@ +<!-- ************************************************************************** +# +# Copyright (c) 2011 Oracle Corporation. +# +# 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 +# +# Contributors: +# +# Nikita Levyankov +# +# +#************************************************************************** --> +<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt"> + <l:layout> + <st:include page="sidepanel.jelly" /> + <l:main-panel> + <j:choose> + <j:when test="${it.cascadingChildrenNames.isEmpty()}"> + <form method="post" action="doDelete"> + ${%Are you sure about deleting the job?} + <f:submit value="${%Yes}" /> + </form> + </j:when> + <j:otherwise> + <h4>${%You can't delete this job because it has cascading children:}</h4> + <ul> + <j:forEach var="job" items="${it.cascadingChildrenNames}"> + <li>${job}</li> + </j:forEach> + </ul> + </j:otherwise> + </j:choose> + </l:main-panel> + </l:layout> +</j:jelly>
\ No newline at end of file diff --git a/hudson-core/src/main/resources/hudson/model/AbstractProject/deleteConfirmationPanel.jelly b/hudson-core/src/main/resources/hudson/model/AbstractProject/deleteConfirmationPanel.jelly index 2b16fc9..e2367b5 100644 --- a/hudson-core/src/main/resources/hudson/model/AbstractProject/deleteConfirmationPanel.jelly +++ b/hudson-core/src/main/resources/hudson/model/AbstractProject/deleteConfirmationPanel.jelly @@ -1,6 +1,6 @@ <!-- ************************************************************************** # -# Copyright (c) 2004-2009 Oracle Corporation. +# Copyright (c) 2004-2011 Oracle Corporation. # # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 @@ -9,16 +9,51 @@ # # Contributors: # -# Winston Prakash +# Winston Prakash, Nikita Levyankov # # #************************************************************************** --> +<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt"> + <script type="text/javascript"> + function onDeleteClick() { + jQuery.ajax({ + url: "${rootUrl}/${it.url}api/json", + dataType: 'json', + success: function(data) { + jQuery('#confirmDialog').show(); + jQuery('#childrenList').hide(); + var cascadingChildren = data.cascadingChildrenNames; + if (cascadingChildren.length != 0) { + var jobList = jQuery("#jobList"); + jobList.html(""); + cascadingChildren.sort(); + for (var i = 0; i < cascadingChildren.length; i++) { + jobList.append("<li>" + cascadingChildren[i] + "</li>"); + } + jQuery('#confirmDialog').hide(); + jQuery('#childrenList').show(); + } + } + }); + onLinkClick("question"); + } + </script> -<div> - <form method="post" action="doDelete"> - <h4>Are you sure you want to delete the Job?.</h4> - <input type="submit" class="yes" value="Yes" /> - <input type="button" class="no" value="No" /> - </form> -</div> + <div> + <form method="post" action="doDelete" id="deleteForm"> + <div id="confirmDialog"> + <h4>Are you sure you want to delete the Job?.</h4> + <input type="submit" class="yes" value="${%Yes}"/> + <input type="button" class="no" value="${%No}"/> + </div> + <div id="childrenList" class="deleteJobDialog" style="display:none"> + <h4>${%You can't delete this job because it has cascading children:}</h4> + <ul id="jobList"> + </ul> + <input type="button" class="no" value="${%Ok}" /> + </div> + </form> + </div> + +</j:jelly> diff --git a/hudson-core/src/main/resources/hudson/model/AbstractProject/sidepanel.jelly b/hudson-core/src/main/resources/hudson/model/AbstractProject/sidepanel.jelly index 2590104..65a13c8 100644 --- a/hudson-core/src/main/resources/hudson/model/AbstractProject/sidepanel.jelly +++ b/hudson-core/src/main/resources/hudson/model/AbstractProject/sidepanel.jelly @@ -1,6 +1,6 @@ <!-- ************************************************************************** # -# Copyright (c) 2004-2009 Oracle Corporation. +# Copyright (c) 2004-2011 Oracle Corporation. # # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 @@ -9,7 +9,7 @@ # # Contributors: # -# Kohsuke Kawaguchi, Erik Ramfelt, Tom Huybrechts, id:cactusman, Yahoo! Inc. +# Kohsuke Kawaguchi, Erik Ramfelt, Tom Huybrechts, id:cactusman, Yahoo! Inc., Nikita Levyankov # # #************************************************************************** --> @@ -46,7 +46,7 @@ } </script> </j:if> - <l:taskWithDialog icon="images/24x24/edit-delete.png" href="${url}/delete" dialogPanel="deleteConfirmationPanel.jelly" title="${%delete(it.pronoun)}" permission="${it.DELETE}" /> + <l:taskWithDialog icon="images/24x24/edit-delete.gif" href="${url}/delete" dialogPanel="deleteConfirmationPanel.jelly" title="${%delete(it.pronoun)}" permission="${it.DELETE}" onclick="onDeleteClick();return false;"/> <j:choose> <j:when test="${h.hasPermission(it,it.CONFIGURE)}"> <l:task icon="images/24x24/setting.png" href="${url}/configure" title="${%Configure}" /> diff --git a/hudson-core/src/test/java/hudson/FunctionsTest.java b/hudson-core/src/test/java/hudson/FunctionsTest.java index 80ec0a9..bcc6c07 100644 --- a/hudson-core/src/test/java/hudson/FunctionsTest.java +++ b/hudson-core/src/test/java/hudson/FunctionsTest.java @@ -16,6 +16,7 @@ package hudson; import hudson.model.FreeStyleProject; +import hudson.model.FreeStyleProjectMock; import hudson.model.Hudson; import hudson.model.Job; import hudson.model.User; @@ -24,7 +25,6 @@ import java.util.List; import junit.framework.Assert; import org.junit.Test; import org.junit.runner.RunWith; -import org.powermock.api.easymock.PowerMock; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @@ -140,4 +140,58 @@ public class FunctionsTest { items.add(parentProject); FreeStyleProject project = Functions.getItemByName(items, TEMPLATE_NAME); assertNotNull(project); - }} + } + @Test + public void testUnlinkProjectFromCascadingParents() { + //Prepare data + FreeStyleProject project1 = new FreeStyleProjectMock("project1"); + FreeStyleProjectMock child1 = new FreeStyleProjectMock("child1"); + child1.setCascadingProject(project1); + String cascadingName = "newCascadingProject"; + Functions.linkCascadingProjectsToChild(child1, cascadingName); + + //Can't unlink from null project + assertFalse(Functions.unlinkProjectFromCascadingParents(null, cascadingName)); + //Can't unlink null cascading name + assertFalse(Functions.unlinkProjectFromCascadingParents(project1, null)); + + //Verify whether cascadingName is present in parent and child + assertTrue(project1.getCascadingChildrenNames().contains(cascadingName)); + assertTrue(child1.getCascadingChildrenNames().contains(cascadingName)); + boolean result = Functions.unlinkProjectFromCascadingParents(child1, cascadingName); + assertTrue(result); + //Name should disappear from hierarchy. + assertFalse(project1.getCascadingChildrenNames().contains(cascadingName)); + assertFalse(child1.getCascadingChildrenNames().contains(cascadingName)); + + Functions.linkCascadingProjectsToChild(project1, cascadingName); + assertTrue(project1.getCascadingChildrenNames().contains(cascadingName)); + result = Functions.unlinkProjectFromCascadingParents(child1, cascadingName); + assertTrue(result); + assertFalse(project1.getCascadingChildrenNames().contains(cascadingName)); + + } + + @Test + public void testLinkCascadingProjectsToChild() { + FreeStyleProject project1 = new FreeStyleProjectMock("project1"); + FreeStyleProjectMock child1 = new FreeStyleProjectMock("child1"); + child1.setCascadingProject(project1); + String cascadingName = "newCascadingProject"; + Functions.linkCascadingProjectsToChild(null, cascadingName); + assertFalse(project1.getCascadingChildrenNames().contains(cascadingName)); + assertFalse(child1.getCascadingChildrenNames().contains(cascadingName)); + + Functions.linkCascadingProjectsToChild(project1, cascadingName); + assertTrue(project1.getCascadingChildrenNames().contains(cascadingName)); + + project1 = new FreeStyleProjectMock("project1"); + child1 = new FreeStyleProjectMock("child1"); + child1.setCascadingProject(project1); + Functions.linkCascadingProjectsToChild(child1, cascadingName); + //Name should be included to all cascading parents up-hierarchy. + assertTrue(project1.getCascadingChildrenNames().contains(cascadingName)); + assertTrue(child1.getCascadingChildrenNames().contains(cascadingName)); + } +} + diff --git a/hudson-war/src/main/webapp/css/style.css b/hudson-war/src/main/webapp/css/style.css index c56c499..dfa890d 100644 --- a/hudson-war/src/main/webapp/css/style.css +++ b/hudson-war/src/main/webapp/css/style.css @@ -987,17 +987,17 @@ table.progress-bar.red td.progress-bar-done { .tag8 { font-size: 1.80em; } .tag9 { font-size: 1.90em; } -/* ========================= "Delete slave" dialog ================== */ -div.deleteSlaveDialog ul { +/* ========================= "Delete job and slave" dialog ================== */ +div.deleteSlaveDialog ul, div.deleteJobDialog ul { text-align:left; padding-left:80px; } -div.deleteSlaveDialog div.radioButtons { +div.deleteSlaveDialog div.radioButtons, div.deleteJobDialog div.radioButtons { padding-bottom:10px; } -div.deleteSlaveDialog h4 { +div.deleteSlaveDialog h4, div.deleteJobDialog h4 { color: #F89938; } /* ======================== "Cascading project" ==========================*/ |

