package hudson.plugins.promoted_builds.integrations.jobdsl; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import com.thoughtworks.xstream.XStream; import hudson.Extension; import hudson.model.AbstractItem; import hudson.model.Item; import hudson.model.Items; import hudson.model.Descriptor.FormException; import hudson.plugins.promoted_builds.JobPropertyImpl; import hudson.util.IOUtils; import hudson.util.XStream2; import javaposse.jobdsl.dsl.helpers.properties.PropertiesContext; import javaposse.jobdsl.plugin.ContextExtensionPoint; import javaposse.jobdsl.plugin.DslEnvironment; import javaposse.jobdsl.plugin.DslExtensionMethod; /** * The Job DSL Extension Point for the Promotions. * See also <a href="https://github.com/jenkinsci/job-dsl-plugin/wiki/Extending-the-DSL">Extending the DSL</a> * * @author Dennis Schulte */ @Extension(optional=true) public class PromotionsExtensionPoint extends ContextExtensionPoint { private static final Logger LOGGER = Logger.getLogger(PromotionsExtensionPoint.class.getName()); private static final XStream XSTREAM = new XStream2(); @DslExtensionMethod(context = PropertiesContext.class) public Object promotions(Runnable closure, DslEnvironment dslEnvironment) throws FormException, IOException { PromotionsContext context = new PromotionsContext(dslEnvironment); executeInContext(closure, context); dslEnvironment.put("processNames", context.names); JobPropertyImpl jobProperty = new JobPropertyImpl(context.names); Map<String,JobDslPromotionProcess> promotionProcesses = new HashMap<String,JobDslPromotionProcess>(); for (String processName : context.names) { PromotionContext promotionContext = context.promotionContexts.get(processName); JobDslPromotionProcess jobDslPromotionProcess = new JobDslPromotionProcess(); jobDslPromotionProcess.setName(processName); jobDslPromotionProcess.setIcon(promotionContext.getIcon()); jobDslPromotionProcess.setAssignedLabel(promotionContext.getRestrict()); jobDslPromotionProcess.setBuildSteps(promotionContext.getActions()); jobDslPromotionProcess.setConditions(promotionContext.getConditions()); promotionProcesses.put(processName,jobDslPromotionProcess); } dslEnvironment.put("promotionProcesses", promotionProcesses); return jobProperty; } @Override public void notifyItemCreated(Item item, DslEnvironment dslEnvironment) { notifyItemCreated(item, dslEnvironment, false); } @SuppressWarnings("unchecked") public void notifyItemCreated(Item item, DslEnvironment dslEnvironment, boolean update) { LOGGER.log(Level.INFO, String.format("Creating promotions for %s", item.getName())); Map<String,JobDslPromotionProcess> promotionProcesses = (Map<String,JobDslPromotionProcess>) dslEnvironment.get("promotionProcesses"); Set<String> names = (Set<String>) dslEnvironment.get("processNames"); if (names != null && names.size() > 0) { for (String name : names) { JobDslPromotionProcess promotionProcess = promotionProcesses.get(name); XSTREAM.registerConverter(new JobDslPromotionProcessConverter(XSTREAM.getMapper(), XSTREAM.getReflectionProvider())); XSTREAM.registerConverter(new ManualConditionConverter(XSTREAM.getMapper(), XSTREAM.getReflectionProvider())); String xml = XSTREAM.toXML(promotionProcess); File dir = new File(item.getRootDir(), "promotions/" + name); File configXml = Items.getConfigFile(dir).getFile(); boolean created = configXml.getParentFile().mkdirs(); String createUpdate; if(created){ createUpdate = "Added"; }else{ createUpdate = "Updated"; } try { InputStream in = new ByteArrayInputStream(xml.getBytes("UTF-8")); IOUtils.copy(in, configXml); LOGGER.log(Level.INFO, String.format(createUpdate + " promotion with name %s for %s", name, item.getName())); update = true; } catch (UnsupportedEncodingException e) { throw new IllegalStateException("Error handling extension code", e); } catch (IOException e) { throw new IllegalStateException("Error handling extension code", e); } } } // Only update if a promotion was actually added, updated, or removed. if (update) { try { LOGGER.log(Level.INFO, String.format("Reloading config for %s", item.getName())); ((AbstractItem) item).doReload(); } catch (Exception e) { throw new IllegalStateException("Unable to cast item to AbstractItem and reload config", e); } } } @Override public void notifyItemUpdated(Item item, DslEnvironment dslEnvironment) { LOGGER.log(Level.INFO, String.format("Updating promotions for %s", item.getName())); @SuppressWarnings("unchecked") Set<String> newPromotions = (Set<String>) dslEnvironment.get("processNames"); File dir = new File(item.getRootDir(), "promotions/"); boolean update = false; // Delete removed promotions if (newPromotions != null) { File[] files = dir.listFiles(); if (files != null) { for (File promotion : files) { if (!newPromotions.contains(promotion.getName())) { boolean deleted = promotion.delete(); if(deleted){ LOGGER.log(Level.INFO, String.format("Deleted promotion with name %s for %s", promotion.getName(), item.getName())); update = true; } } } } } // Delegate to create-method this.notifyItemCreated(item, dslEnvironment, update); } }