All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hudsonci.plugins.team.cli.CopyTeamCommand Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2013 Hudson.
 * 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:
 *    Hudson - initial API and implementation and/or initial documentation
 */

package org.hudsonci.plugins.team.cli;

import hudson.Extension;
import hudson.XmlFile;
import hudson.cli.CLICommand;
import hudson.model.Failure;
import hudson.model.Hudson;
import hudson.model.Job;
import hudson.model.TopLevelItem;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.eclipse.hudson.security.team.Team;
import org.eclipse.hudson.security.team.TeamManager;
import org.eclipse.hudson.security.team.TeamManager.TeamAlreadyExistsException;
import org.eclipse.hudson.security.team.TeamManager.TeamNotFoundException;
import org.eclipse.hudson.security.team.TeamNode;
import org.eclipse.hudson.security.team.TeamView;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;

/**
 * Copy a team and its jobs from the command line. User must be sys admin.
 * 

EMAIL * Email are replaced with contents of email argument. *
 * 
 *   
 *     
 *       hudson-tasks-Mailer
 *       
 *         
 *           ${email}
 *           false
 *           false
 *         
 *         false
 *         true
 *       
 *     
 * 
* If email not specified, replace entire entry with: *
 * 
 *   hudson-tasks-Mailer
 *   
 *     false
 *     false
 *   
 * 
 * 
* Cascading project names qualified with the old team name are requalified * with the new team name. E.g., for copy-team Team1 TeamX *
 * 
 *   Team1.JobBill2
 *   
 *     Team1.JobBill5
 *   
 * 
* Is converted to: *
 * 
 *   TeamX.JobBill2
 *   
 *     TeamX.JobBill5
 *   
 * 
* If build trigger is specified, replace old team name with new team name, e.g., *
 * 
 *   
 *     
 *       hudson-tasks-BuildTrigger
 *       
 *         
 *           Team1.JobBill4, Team1.JobBill5
 * 
* Is converted to: *
 * 
 *   
 *     
 *       hudson-tasks-BuildTrigger
 *       
 *         
 *           TeamX.JobBill4, TeamX.JobBill5
 * 
* Note that project names that are not qualified with the old team name * are untouched. *

-nodes option * * * * * * * * * * * * * *
ValueMeaning
moveMove nodes owned by the from team to the to team.visibleMake nodes owned by the from team visible to the to teamignoreDo nothing about nodes owned by the from team (default)
* *

-views option *

* * * * * * * * * * * *
ValueMeaning
moveMove views owned by the from team to the to team.visibleMake views owned by the from team visible to the to teamignoreDo nothing about views owned by the from team (default)
* @author Bob Foster */ @Extension public class CopyTeamCommand extends CLICommand { @Override public String getShortDescription() { return "Copy a team and its jobs to a newly created team"; } @Argument(metaVar = "FROM", usage = "Team name to copy (required)", required=true, index=0) public String from; @Argument(metaVar = "TO", usage = "Team name to create (required)", required=true, index=1) public String to; @Argument(metaVar = "EMAIL", usage = "Email recipients separated by commas (optional); if not specified, recipients will be removed", required=false, index=2) public String email; @Option(name = "-n", aliases="--nodes", usage = "MOVE (move nodes to new team), VISIBLE (make nodes visible to new team), IGNORE (ignore nodes - default), ") public String nodes; @Option(name = "-v", aliases="--views", usage = "MOVE (move views to new team), VISIBLE (make views visible to new team), IGNORE (ignore views - default), ") public String views; protected int run() throws Exception { Hudson h = Hudson.getInstance(); if (!h.isTeamManagementEnabled()) { stderr.println("Team management is not enabled"); return -1; } TeamManager teamManager = h.getTeamManager(); if (!teamManager.isCurrentUserSysAdmin()) { stderr.println("User not authorized to create team"); return -1; } Team fromTeam; try { fromTeam = teamManager.findTeam(from); } catch (TeamNotFoundException e) { stderr.println("From team "+from+" not found"); return -1; } if (nodes != null && !("move".equalsIgnoreCase(nodes) || "visible".equalsIgnoreCase(nodes) || "ignore".equalsIgnoreCase(nodes))) { stderr.println("nodes must be one of move, visible or ignore"); } if (views != null && !("move".equalsIgnoreCase(views) || "visible".equalsIgnoreCase(views) || "ignore".equalsIgnoreCase(views))) { stderr.println("views must be one of move, visible or ignore"); } Team toTeam = null; try { toTeam = teamManager.createTeam(to); } catch (IOException ex) { stderr.println(ex.getMessage()); return -1; } catch (TeamAlreadyExistsException ex) { stderr.println("To team "+to+" already exists"); return -1; } Set jobNames = fromTeam.getJobNames(); for (String jobName : jobNames) { String unqualifiedName = teamManager.getUnqualifiedJobName(jobName); TopLevelItem item = h.getItem(jobName); if (item instanceof Job) { Job job = (Job) item; XmlFile file = job.getConfigFile(); InputStream in; try { in = fixConfigFile(file, from, to, email); } catch (Failure ex) { stderr.println("Error reading config.xml for job "+jobName); stderr.println(ex.getMessage()); return -1; } h.createProjectFromXML(unqualifiedName, to, in); } } if (nodes != null) { if ("move".equalsIgnoreCase(nodes)) { for (String nodeName : fromTeam.getNodeNames()) { teamManager.moveNode(fromTeam, toTeam, nodeName); } } else if ("visible".equalsIgnoreCase(nodes)) { for (TeamNode teamNode : fromTeam.getNodes()) { teamManager.addNodeVisibility(teamNode, toTeam.getName()); // Assume target team wants to be able to use the node. teamManager.setNodeEnabled(teamNode.getId(), toTeam, true); } } } if (views != null) { if ("move".equalsIgnoreCase(views)) { for (String viewName : fromTeam.getViewNames()) { teamManager.moveView(fromTeam, toTeam, viewName); } } else if ("visible".equalsIgnoreCase(nodes)) { for (TeamView teamView : fromTeam.getViews()) { teamManager.addViewVisibility(teamView, toTeam.getName()); } } } return 0; } /* * This method intentionally does not use XStream or any of the objects * associated with various elements in the config.xml file, dealing * instead with the "raw" XML, because the objects and their methods * have too many unforseeable side effects. */ private InputStream fixConfigFile(XmlFile file, String oldTeam, String newTeam, String email) { InputStream in = null; String oldPrefix = oldTeam + TeamManager.TEAM_SEPARATOR; String newPrefix = newTeam + TeamManager.TEAM_SEPARATOR; try { in = new FileInputStream(file.getFile()); SAXReader reader = new SAXReader(); Document doc = reader.read(in); Element root = doc.getRootElement(); // The root element name varies by project type, e.g., // project, matrix-project, etc. Code assumes that // following elements are common to all project types. // Cascading Element cascadingParent = root.element("cascadingProjectName"); if (cascadingParent != null) { fixTeamName(cascadingParent, oldPrefix, newPrefix); } Element cascadingChildren = root.element("cascadingChildrenNames"); if (cascadingChildren != null) { for (Object elem : cascadingChildren.elements("string")) { fixTeamName((Element) elem, oldPrefix, newPrefix); } } // Properties (open-ended problem) Element properties = root.element("project-properties"); if (properties == null) { throw new Failure("Project has no "); } List removeEntries = new ArrayList(); for (Object ent : properties.elements("entry")) { Element entry = (Element) ent; Element extProp = entry.element("external-property"); Element origValue = extProp != null ? extProp.element("originalValue") : null; Element str = entry.element("string"); if (str != null) { String propName = str.getTextTrim(); if ("hudson-tasks-Mailer".equals(propName)) { // email if (extProp != null) { if (email == null) { // A recent fix removes entries that are not specified removeEntries.add(entry); /* // Replace entire entry entry.remove(extProp); extProp = entry.addElement("external-property"); Element propOver = extProp.addElement("propertyOverridden"); propOver.setText("false"); Element modified = extProp.addElement("modified"); modified.setText("false"); */ } else if (origValue != null) { fixEmailProperty(origValue, email); } } } else if ("hudson-tasks-BuildTrigger".equals(propName)) { // trigger if (origValue != null) { fixTriggerProperty(origValue, oldPrefix, newPrefix); } } else if ("builders".equals(propName)) { // can be many of these Element describableList = entry.element("describable-list-property"); origValue = describableList != null ? describableList.element("originalValue") : null; // copyartifact List artifacts = origValue != null ? origValue.elements("hudson.plugins.copyartifact.CopyArtifact") : null; if (artifacts != null) { for (Object obj : artifacts) { Element copyArtifact = (Element) obj; Element projectName = copyArtifact.element("projectName"); fixTeamName(projectName, oldPrefix, newPrefix); } } // multijob List multiJob = origValue != null ? origValue.elements("com.tikal.jenkins.plugins.multijob.MultiJobBuilder") : null; for (Object obj : multiJob) { Element builder = (Element) obj; List jobs = builder.elements("phaseJobs"); if (jobs != null) { for (Object j : jobs) { Element job = (Element) j; List configs = job.elements("com.tikal.jenkins.plugins.multijob.PhaseJobsConfig"); if (configs != null) { for (Object c : configs) { Element config = (Element) c; Element jobName = config.element("jobName"); fixTeamName(jobName, oldPrefix, newPrefix); } } } } } } else if ("hudson-plugins-redmine-RedmineProjectProperty".equals(propName)) { Element baseProp = entry.element("base-property"); Element projectName = baseProp != null ? baseProp.element("projectName") : null; if (projectName != null) { fixTeamName(projectName, oldPrefix, newPrefix); } } } } for (Element entry : removeEntries) { properties.remove(entry); } StringWriter writer = new StringWriter(); doc.write(writer); return new ByteArrayInputStream(writer.toString().getBytes("UTF-8")); } catch (FileNotFoundException ex) { throw new Failure("File not found"); } catch (DocumentException ex) { throw new Failure("Unable to parse document"); } catch (IOException ex) { throw new Failure("Document write failed"); } finally { try { in.close(); } catch (IOException ex) { ; } } } private void fixTeamName(Element element, String oldPrefix, String newPrefix) { String jobName = element.getTextTrim(); if (jobName.startsWith(oldPrefix)) { element.setText(newPrefix+jobName.substring(oldPrefix.length())); } } private void fixTriggerProperty(Element origValue, String oldPrefix, String newPrefix) { Element cp = origValue.element("childProjects"); String childProjects = cp.getTextTrim(); List children = new ArrayList(); StringTokenizer st = new StringTokenizer(childProjects, ", "); boolean changed = false; while (st.hasMoreTokens()) { String child = st.nextToken(); if (child.startsWith(oldPrefix)) { changed = true; child = newPrefix + child.substring(oldPrefix.length()); } children.add(child); } if (changed) { childProjects = StringUtils.join(children, ", "); cp.setText(childProjects); } } private void fixEmailProperty(Element origValue, String email) { Element recipients = origValue.element("recipients"); if (recipients != null) { recipients.setText(email); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy