private boolean updateExistingJob(AbstractProject<?, ?> project, String config) { boolean created; // Leverage XMLUnit to perform diffs Diff diff; try { String oldJob = project.getConfigFile().asString(); diff = XMLUnit.compareXML(oldJob, config); if (diff.similar()) { LOGGER.log(Level.FINE, String.format("Project %s is identical", project.getName())); return false; } } catch (Exception e) { // It's not a big deal if we can't diff, we'll just move on LOGGER.warning(e.getMessage()); } // TODO Perform comparison between old and new, and print to console // TODO Print out, for posterity, what the user might have changed, in the format of the DSL LOGGER.log(Level.FINE, String.format("Updating project %s as %s", project.getName(), config)); StreamSource streamSource = new StreamSource(new StringReader(config)); // TODO use real xmlReader try { project.updateByXml(streamSource); created = true; } catch (IOException ioex) { LOGGER.log(Level.WARNING, String.format("Error writing updated project to file."), ioex); created = false; } return created; }
@Override public CauseOfBlockage canRun(Queue.Item item) { // Skip locking for multiple configuration projects, // only the child jobs will actually lock resources. if (item.task instanceof MatrixProject) return null; AbstractProject<?, ?> project = Utils.getProject(item); if (project == null) return null; LockableResourcesStruct resources = Utils.requiredResources(project); if (resources == null || (resources.required.isEmpty() && resources.label.isEmpty())) { return null; } int resourceNumber; try { resourceNumber = Integer.parseInt(resources.requiredNumber); } catch (NumberFormatException e) { resourceNumber = 0; } LOGGER.finest(project.getName() + " trying to get resources with these details: " + resources); if (resourceNumber > 0 || !resources.label.isEmpty()) { Map<String, Object> params = new HashMap<String, Object>(); if (item.task instanceof MatrixConfiguration) { MatrixConfiguration matrix = (MatrixConfiguration) item.task; params.putAll(matrix.getCombination()); } List<LockableResource> selected = LockableResourcesManager.get() .queue(resources, item.id, project.getFullName(), resourceNumber, params, LOGGER); if (selected != null) { LOGGER.finest(project.getName() + " reserved resources " + selected); return null; } else { LOGGER.finest(project.getName() + " waiting for resources"); return new BecauseResourcesLocked(resources); } } else { if (LockableResourcesManager.get().queue(resources.required, item.id)) { LOGGER.finest(project.getName() + " reserved resources " + resources.required); return null; } else { LOGGER.finest(project.getName() + " waiting for resources " + resources.required); return new BecauseResourcesLocked(resources); } } }
public InheritanceParametersDefinitionProperty( AbstractProject<?, ?> owner, ParametersDefinitionProperty other) { this(owner, other.getParameterDefinitions()); // Then, we copy the scope if (other instanceof InheritanceParametersDefinitionProperty) { InheritanceParametersDefinitionProperty ipdp = (InheritanceParametersDefinitionProperty) other; ipdp.scopeLock.readLock().lock(); this.scopeLock.writeLock().lock(); try { for (String pName : ipdp.fullScope.keySet()) { List<ScopeEntry> oLst = ipdp.fullScope.get(pName); if (oLst == null) { continue; } LinkedList<ScopeEntry> newLst = new LinkedList<ScopeEntry>(); for (ScopeEntry entry : oLst) { newLst.add(new ScopeEntry(entry.owner, entry.param)); } this.fullScope.put(pName, newLst); } } finally { this.scopeLock.writeLock().unlock(); ipdp.scopeLock.readLock().unlock(); } } else { this.addScopedParameterDefinitions( (owner != null) ? owner.getName() : "", other.getParameterDefinitions()); } }
public void populate(@NotNull AbstractProject project) { synchronized (populateLock) { Run lastBuild = project.getLastBuild(); if (lastBuild == null) { return; } if (lastBuild.getNumber() <= oldest) { return; } for (int number = lastBuild.getNumber(); number > oldest; number--) { Run build = project.getBuildByNumber(number); if (build == null) { continue; } String externalizableId = build.getExternalizableId(); size++; put("projectName", project.getName(), externalizableId); populateWithChangeInformation(build, externalizableId); populateWithCauseInformation(build, externalizableId); populateWithParameters(build, externalizableId); } oldest = lastBuild.getNumber(); } }
@Test public void assertJobNameWithoutComputerIsResolved() { when(project.getName()).thenReturn("ThisIsAJob"); BuildVariableResolver resolver = new BuildVariableResolver(project); assertEquals("Variable resolution was incorrect", "ThisIsAJob", resolver.resolve("JOB_NAME")); assertNull("Variable resolution was performed", resolver.resolve("NONE_EXISTING_KEY")); }
@Test public void assertJobNameIsResolved() { when(project.getName()).thenReturn("ThisIsAJob"); BuildVariableResolver resolver = new BuildVariableResolver(project, computer); assertEquals("Variable resolution was incorrect", "ThisIsAJob", resolver.resolve("JOB_NAME")); verifyZeroInteractions(computer); }
/* * Determine the Hudson parameter values from the OSLC parameter instances * in the AutomationRequest */ private List<ParameterValue> getParameterValues( AbstractProject<?, ?> project, ParameterInstance[] parameters) { ParametersDefinitionProperty pp = project.getProperty(ParametersDefinitionProperty.class); if (pp == null) { LOG.log(Level.FINE, "Job does not take parameters: " + project.getName()); throw HttpResponses.status( HttpServletResponse.SC_BAD_REQUEST); // This build is not parameterized. } HashMap<String, String> inputMap = new HashMap<String, String>(); for (ParameterInstance param : parameters) { inputMap.put(param.getName(), param.getValue()); } List<ParameterValue> values = new ArrayList<ParameterValue>(); for (ParameterDefinition def : pp.getParameterDefinitions()) { String inputValue = inputMap.get(def.getName()); if (inputValue == null) { ParameterValue defaultValue = def.getDefaultParameterValue(); if (defaultValue == null) { LOG.log( Level.FINE, "Missing parameter " + def.getName() + " for job " + project.getName()); throw HttpResponses.status(HttpServletResponse.SC_BAD_REQUEST); } values.add(defaultValue); } else { if (def instanceof SimpleParameterDefinition) { SimpleParameterDefinition simple = (SimpleParameterDefinition) def; values.add(simple.createValue(inputValue)); } else { LOG.log( Level.WARNING, "Unsupported parameter type with name " + def.getName() + " for project " + project.getName()); throw HttpResponses.status(HttpServletResponse.SC_NOT_IMPLEMENTED); } } } return values; }
@Override public Collection<? extends Action> createFor(AbstractProject target) { try { ArrayList<abbrResult> results = readTestsFile(StabilityTestDataPublisher.getFilePath("Run"), target.getName()); return Collections.singleton(new AllTestsHistoriesAction(results, target)); } catch (IOException e) { return Collections.singleton(new AllTestsHistoriesAction(target)); } }
/** * Actually build a project, passing in parameters where appropriate * * @param project * @return */ protected final boolean performBuildProject(AbstractProject<?, ?> project) { if (!project.hasPermission(AbstractProject.BUILD)) { LOGGER.log(Level.WARNING, "Insufficient permission to build job '" + project.getName() + "'"); return false; } if (action.equals(BuildAction.POLL_SCM)) { project.schedulePolling(); return true; } // no user parameters provided, just build it if (param == null) { project.scheduleBuild(new Cause.UserIdCause()); return true; } ParametersDefinitionProperty pp = (ParametersDefinitionProperty) project.getProperty(ParametersDefinitionProperty.class); // project does not except any parameters, just build it if (pp == null) { project.scheduleBuild(new Cause.UserIdCause()); return true; } List<ParameterDefinition> parameterDefinitions = pp.getParameterDefinitions(); List<ParameterValue> values = new ArrayList<ParameterValue>(); for (ParameterDefinition paramDef : parameterDefinitions) { if (!(paramDef instanceof StringParameterDefinition)) { // TODO add support for other parameter types values.add(paramDef.getDefaultParameterValue()); continue; } StringParameterDefinition stringParamDef = (StringParameterDefinition) paramDef; ParameterValue value; // Did user supply this parameter? if (param.containsKey(paramDef.getName())) { value = stringParamDef.createValue(param.get(stringParamDef.getName())); } else { // No, then use the default value value = stringParamDef.createValue(stringParamDef.getDefaultValue()); } values.add(value); } Jenkins.getInstance().getQueue().schedule(pp.getOwner(), 1, new ParametersAction(values)); return true; }
public JoinAction( JoinTrigger joinTrigger, BuildTrigger buildTrigger, ArrayList<String> otherDownstream) { this.pendingDownstreamProjects = new LinkedList<String>(); if (buildTrigger != null) { for (AbstractProject project : buildTrigger.getChildProjects()) { if (!project.isDisabled()) { this.pendingDownstreamProjects.add(project.getName()); } } } for (String proj : otherDownstream) { this.pendingDownstreamProjects.add(proj.trim()); } this.joinProjects = joinTrigger.getJoinProjectsValue(); this.joinPublishers = joinTrigger.getJoinPublishers(); this.evenIfDownstreamUnstable = joinTrigger.getEvenIfDownstreamUnstable(); this.completedDownstreamProjects = new LinkedList<String>(); this.consideredBuilds = new LinkedList<String>(); this.overallResult = Result.SUCCESS; }
public synchronized void checkPendingDownstream( AbstractBuild<?, ?> owner, TaskListener listener) { if (pendingDownstreamProjects.isEmpty()) { listener.getLogger().println("All downstream projects complete!"); Result threshold = this.evenIfDownstreamUnstable ? Result.UNSTABLE : Result.SUCCESS; if (this.overallResult.isWorseThan(threshold)) { listener.getLogger().println("Minimum result threshold not met for join project"); } else { // Construct a launcher since CopyArchiver wants to get the // channel from it. We use the channel of the node where the // splitProject was built on. final Launcher launcher = new NoopLauncher(listener, owner); for (Publisher pub : this.joinPublishers) { try { pub.perform(owner, launcher, (BuildListener) listener); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } if (!JoinTrigger.canDeclare(owner.getProject())) { List<AbstractProject> projects = Items.fromNameList(joinProjects, AbstractProject.class); for (AbstractProject project : projects) { listener.getLogger().println("Scheduling join project: " + project.getName()); project.scheduleBuild(new JoinCause(owner)); } } } } else { listener .getLogger() .println( "Project " + owner.getProject().getName() + " still waiting for " + pendingDownstreamProjects.size() + " builds to complete"); } }
@Override public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException { listener.getLogger().println("[htmlpublisher] Archiving HTML reports..."); // Grab the contents of the header and footer as arrays ArrayList<String> headerLines; ArrayList<String> footerLines; try { headerLines = this.readFile("/htmlpublisher/HtmlPublisher/header.html"); footerLines = this.readFile("/htmlpublisher/HtmlPublisher/footer.html"); } catch (FileNotFoundException e1) { e1.printStackTrace(); return false; } catch (IOException e1) { e1.printStackTrace(); return false; } for (int i = 0; i < this.reportTargets.size(); i++) { // Create an array of lines we will eventually write out, initially the header. ArrayList<String> reportLines = new ArrayList<String>(headerLines); HtmlPublisherTarget reportTarget = this.reportTargets.get(i); boolean keepAll = reportTarget.getKeepAll(); FilePath archiveDir = build .getWorkspace() .child(resolveParametersInString(build, listener, reportTarget.getReportDir())); FilePath targetDir = reportTarget.getArchiveTarget(build); String levelString = keepAll ? "BUILD" : "PROJECT"; listener .getLogger() .println( "[htmlpublisher] Archiving at " + levelString + " level " + archiveDir + " to " + targetDir); // The index name might be a comma separated list of names, so let's figure out all the pages // we should index. String[] csvReports = resolveParametersInString(build, listener, reportTarget.getReportFiles()).split(","); ArrayList<String> reports = new ArrayList<String>(); for (int j = 0; j < csvReports.length; j++) { String report = csvReports[j]; report = report.trim(); // Ignore blank report names caused by trailing or double commas. if (report.equals("")) { continue; } reports.add(report); String tabNo = "tab" + (j + 1); // Make the report name the filename without the extension. int end = report.lastIndexOf("."); String reportName; if (end > 0) { reportName = report.substring(0, end); } else { reportName = report; } String tabItem = "<li id=\"" + tabNo + "\" class=\"unselected\" onclick=\"updateBody('" + tabNo + "');\" value=\"" + report + "\">" + reportName + "</li>"; reportLines.add(tabItem); } // Add the JS to change the link as appropriate. String hudsonUrl = Hudson.getInstance().getRootUrl(); AbstractProject job = build.getProject(); reportLines.add( "<script type=\"text/javascript\">document.getElementById(\"hudson_link\").innerHTML=\"Back to " + job.getName() + "\";</script>"); // If the URL isn't configured in Hudson, the best we can do is attempt to go Back. if (hudsonUrl == null) { reportLines.add( "<script type=\"text/javascript\">document.getElementById(\"hudson_link\").onclick = function() { history.go(-1); return false; };</script>"); } else { String jobUrl = hudsonUrl + job.getUrl(); reportLines.add( "<script type=\"text/javascript\">document.getElementById(\"hudson_link\").href=\"" + jobUrl + "\";</script>"); } reportLines.add( "<script type=\"text/javascript\">document.getElementById(\"zip_link\").href=\"*zip*/" + reportTarget.getSanitizedName() + ".zip\";</script>"); try { if (!archiveDir.exists()) { listener.error("Specified HTML directory '" + archiveDir + "' does not exist."); build.setResult(Result.FAILURE); return true; } else if (!keepAll) { // We are only keeping one copy at the project level, so remove the old one. targetDir.deleteRecursive(); } if (archiveDir.copyRecursiveTo("**/*", targetDir) == 0) { listener.error( "Directory '" + archiveDir + "' exists but failed copying to '" + targetDir + "'."); if (build.getResult().isBetterOrEqualTo(Result.UNSTABLE)) { // If the build failed, don't complain that there was no coverage. // The build probably didn't even get to the point where it produces coverage. listener.error("This is especially strange since your build otherwise succeeded."); } build.setResult(Result.FAILURE); return true; } } catch (IOException e) { Util.displayIOException(e, listener); e.printStackTrace(listener.fatalError("HTML Publisher failure")); build.setResult(Result.FAILURE); return true; } reportTarget.handleAction(build); // Now add the footer. reportLines.addAll(footerLines); // And write this as the index try { writeFile(reportLines, new File(targetDir.getRemote(), reportTarget.getWrapperName())); } catch (IOException e) { e.printStackTrace(); } } return true; }
@Override public int compare(AbstractProject a, AbstractProject b) { return a.getName().compareToIgnoreCase(b.getName()); }
/** Uses generatedJobs as existing data, so call before updating generatedJobs. */ private Set<String> updateTemplates( AbstractBuild<?, ?> build, BuildListener listener, Set<GeneratedJob> freshJobs) throws IOException { AbstractProject<?, ?> seedJob = build.getProject(); Set<String> freshTemplates = getTemplates(freshJobs); Set<String> existingTemplates = getTemplates(extractGeneratedObjects(seedJob, GeneratedJobsAction.class)); Set<String> newTemplates = Sets.difference(freshTemplates, existingTemplates); Set<String> removedTemplates = Sets.difference(existingTemplates, freshTemplates); logItems(listener, "Existing templates", existingTemplates); logItems(listener, "New templates", newTemplates); logItems(listener, "Unreferenced templates", removedTemplates); // Collect information about the templates we loaded final String seedJobName = seedJob.getName(); DescriptorImpl descriptor = Jenkins.getInstance().getDescriptorByType(DescriptorImpl.class); boolean descriptorMutated = false; // Clean up for (String templateName : removedTemplates) { Collection<SeedReference> seedJobReferences = descriptor.getTemplateJobMap().get(templateName); Collection<SeedReference> matching = Collections2.filter(seedJobReferences, new SeedNamePredicate(seedJobName)); if (!matching.isEmpty()) { seedJobReferences.removeAll(matching); descriptorMutated = true; } } // Ensure we have a reference for (String templateName : freshTemplates) { Collection<SeedReference> seedJobReferences = descriptor.getTemplateJobMap().get(templateName); Collection<SeedReference> matching = Collections2.filter(seedJobReferences, new SeedNamePredicate(seedJobName)); AbstractProject templateProject = getLookupStrategy().getItem(seedJob, templateName, AbstractProject.class); final String digest = Util.getDigestOf(new FileInputStream(templateProject.getConfigFile().getFile())); if (matching.size() == 1) { // Just update digest SeedReference ref = Iterables.get(matching, 0); if (digest.equals(ref.getDigest())) { ref.setDigest(digest); descriptorMutated = true; } } else { if (matching.size() > 1) { // Not sure how there could be more one, throw it all away and start over seedJobReferences.removeAll(matching); } seedJobReferences.add(new SeedReference(templateName, seedJobName, digest)); descriptorMutated = true; } } if (descriptorMutated) { descriptor.save(); } return freshTemplates; }