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;
  }
  /**
   * visit project chain, from current through parents.
   *
   * @param visitor
   * @param run
   */
  public static void traverseChain(HudsonVisitor visitor, Run run) {
    if (run == null) return;

    traverse(visitor, run);

    RepositoryAction repositoryAction = run.getAction(RepositoryAction.class);

    if (repositoryAction != null) {
      if (repositoryAction instanceof ProjectRepositoryAction) {
        final ProjectRepositoryAction projectRepositoryAction =
            (ProjectRepositoryAction) repositoryAction;

        AbstractProject item =
            (AbstractProject)
                Hudson.getInstance().getItem(projectRepositoryAction.getProjectName());

        Optional<Run> r =
            Iterables.tryFind(
                item.getBuilds(),
                new Predicate<Run>() {
                  public boolean apply(Run run) {
                    return run.getNumber() == projectRepositoryAction.getBuildNumber();
                  }
                });

        if (r.isPresent()) traverseChain(visitor, r.get());
      }
    }
  }
  private void build(GHPullRequest pr, GHUser buildRequester, TriggerCause cause)
      throws IOException {
    ArrayList<ParameterValue> parameters = getDefaultBuildParameters();
    parameters.add(new StringParameterValue(PR_COMMIT, pr.getHead().getSha()));
    parameters.add(new StringParameterValue(PR_BRANCH, pr.getHead().getRef()));
    if (buildRequester != null) {
      parameters.add(new StringParameterValue(BUILD_REQUESTER, buildRequester.getLogin()));
      if (buildRequester.getEmail() != null) {
        parameters.add(new StringParameterValue(BUILD_REQUEST_EMAIL, buildRequester.getEmail()));
      }
    }
    parameters.add(new StringParameterValue(PR_NUMBER, String.valueOf(pr.getNumber())));
    parameters.add(new StringParameterValue(PR_MERGE_BRANCH, pr.getBase().getRef()));
    parameters.add(new StringParameterValue(PR_OWNER, pr.getUser().getLogin()));
    if (pr.getUser().getEmail() != null) {
      parameters.add(new StringParameterValue(PR_OWNER_EMAIL, pr.getUser().getEmail()));
    }
    final StringParameterValue prUrlParam =
        new StringParameterValue(PR_URL, pr.getHtmlUrl().toString());
    parameters.add(prUrlParam);

    project.scheduleBuild2(
        project.getQuietPeriod(),
        cause,
        new ParametersAction(parameters),
        getBuildData(prUrlParam),
        new RevisionParameterAction(pr.getHead().getSha()));
  }
  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();
    }
  }
Example #5
0
 public void run() {
   String threadName = Thread.currentThread().getName();
   Thread.currentThread().setName("SCM polling for " + job);
   try {
     startTime = System.currentTimeMillis();
     if (runPolling()) {
       AbstractProject p = job.asProject();
       String name = " #" + p.getNextBuildNumber();
       SCMTriggerCause cause;
       try {
         cause = new SCMTriggerCause(getLogFile());
       } catch (IOException e) {
         LOGGER.log(WARNING, "Failed to parse the polling log", e);
         cause = new SCMTriggerCause();
       }
       if (p.scheduleBuild(p.getQuietPeriod(), cause, additionalActions)) {
         LOGGER.info("SCM changes detected in " + job.getName() + ". Triggering " + name);
       } else {
         LOGGER.info(
             "SCM changes detected in " + job.getName() + ". Job is already in the queue");
       }
     }
   } finally {
     Thread.currentThread().setName(threadName);
   }
 }
  public AbstractProject<?, ?> getParentProject() {
    AbstractProject<?, ?> context = null;
    List<AbstractProject> jobs = Jenkins.getInstance().getAllItems(AbstractProject.class);

    for (AbstractProject<?, ?> project : jobs) {
      if (!(project instanceof TopLevelItem)) continue;

      ParametersDefinitionProperty property =
          project.getProperty(ParametersDefinitionProperty.class);

      if (property != null) {
        List<ParameterDefinition> parameterDefinitions = property.getParameterDefinitions();

        if (parameterDefinitions != null) {
          for (ParameterDefinition pd : parameterDefinitions) {

            if (pd instanceof GitParameterDefinition
                && ((GitParameterDefinition) pd).compareTo(this) == 0) {

              context = project;
              break;
            }
          }
        }
      }
    }

    return context;
  }
  /**
   * Tests a scenario when two builds are successful and both configured to be skipped. Expected
   * outcome is that {@link BuildMemory.MemoryImprint#wereAllBuildsSuccessful()} will return true.
   * As before the skip vote feature was implemented.
   */
  @Test
  public void testWereAllBuildsSuccessfulTwoSuccessfulBothSkipped() {
    PatchsetCreated event = Setup.createPatchsetCreated();
    BuildMemory instance = new BuildMemory();

    AbstractProject project = mock(AbstractProject.class);
    SkipVote skipVote = new SkipVote(true, false, false, false);
    GerritTrigger trigger = mock(GerritTrigger.class);
    when(trigger.getSkipVote()).thenReturn(skipVote);
    when(project.getTrigger(eq(GerritTrigger.class))).thenReturn(trigger);
    AbstractBuild build = mock(AbstractBuild.class);
    when(build.getProject()).thenReturn(project);
    when(build.getResult()).thenReturn(Result.SUCCESS);
    instance.started(event, build);

    AbstractProject project2 = mock(AbstractProject.class);
    skipVote = new SkipVote(true, false, false, false);
    trigger = mock(GerritTrigger.class);
    when(trigger.getSkipVote()).thenReturn(skipVote);
    when(project2.getTrigger(eq(GerritTrigger.class))).thenReturn(trigger);
    AbstractBuild build2 = mock(AbstractBuild.class);
    when(build2.getProject()).thenReturn(project2);
    when(build2.getResult()).thenReturn(Result.SUCCESS);
    instance.started(event, build2);

    instance.completed(event, build);
    instance.completed(event, build2);

    MemoryImprint memoryImprint = instance.getMemoryImprint(event);
    assertTrue(memoryImprint.wereAllBuildsSuccessful());
  }
        @Override
        public void before() throws Throwable {
          super.before();

          content = new JellyScriptContent();
          listener = StreamTaskListener.fromStdout();

          publisher = new ExtendedEmailPublisher();
          publisher.defaultContent =
              "For only 10 easy payment of $69.99 , AWESOME-O 4000 can be yours!";
          publisher.defaultSubject = "How would you like your very own AWESOME-O 4000?";
          publisher.recipientList = "*****@*****.**";

          Field f = ExtendedEmailPublisherDescriptor.class.getDeclaredField("defaultBody");
          f.setAccessible(true);
          f.set(publisher.getDescriptor(), "Give me $4000 and I'll mail you a check for $40,000!");
          f = ExtendedEmailPublisherDescriptor.class.getDeclaredField("defaultSubject");
          f.setAccessible(true);
          f.set(publisher.getDescriptor(), "Nigerian needs your help!");

          f = ExtendedEmailPublisherDescriptor.class.getDeclaredField("recipientList");
          f.setAccessible(true);
          f.set(publisher.getDescriptor(), "*****@*****.**");

          f = ExtendedEmailPublisherDescriptor.class.getDeclaredField("hudsonUrl");
          f.setAccessible(true);
          f.set(publisher.getDescriptor(), "http://localhost/");

          build = mock(AbstractBuild.class);
          AbstractProject project = mock(AbstractProject.class);
          DescribableList publishers = mock(DescribableList.class);
          when(publishers.get(ExtendedEmailPublisher.class)).thenReturn(publisher);
          when(project.getPublishersList()).thenReturn(publishers);
          when(build.getProject()).thenReturn(project);
        }
 protected Future schedule(AbstractBuild<?, ?> build, AbstractProject project, List<Action> list)
     throws InterruptedException, IOException {
   return project.scheduleBuild2(
       project.getQuietPeriod(),
       new UpstreamCause((Run) build),
       list.toArray(new Action[list.size()]));
 }
Example #10
0
  private void setupRemoteFolderDiff(
      RemoteFolderDiff diff, AbstractProject project, Set<String> allowDeleteList) {
    Run lastBuild = project.getLastBuild();
    if (null == lastBuild) {
      diff.setLastBuildTime(0);
      diff.setLastSuccessfulBuildTime(0);
    } else {
      diff.setLastBuildTime(lastBuild.getTimestamp().getTimeInMillis());
      Run lastSuccessfulBuild = project.getLastSuccessfulBuild();
      if (null == lastSuccessfulBuild) {
        diff.setLastSuccessfulBuildTime(-1);
      } else {
        diff.setLastSuccessfulBuildTime(lastSuccessfulBuild.getTimestamp().getTimeInMillis());
      }
    }

    diff.setSrcPath(path);

    if (filterEnabled) {
      if (includeFilter) diff.setIncludeFilter(filters);
      else diff.setExcludeFilter(filters);
    }

    diff.setAllowDeleteList(allowDeleteList);
  }
  private void handlePullRequestEvent(String payload) throws IOException {

    GitHub gitHub = createGitHub(JSONObject.fromObject(payload));

    if (gitHub == null) {
      return;
    }

    GHEventPayload.PullRequest pullRequest =
        gitHub.parseEventPayload(new StringReader(payload), GHEventPayload.PullRequest.class);

    if (SUPPORTED_EVENTS.contains(pullRequest.getAction())) {
      Authentication old = SecurityContextHolder.getContext().getAuthentication();
      SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM);
      try {
        for (AbstractProject<?, ?> job : Jenkins.getInstance().getAllItems(AbstractProject.class)) {
          PullRequestBuildTrigger trigger = job.getTrigger(PullRequestBuildTrigger.class);
          if (trigger != null && trigger.getBuildHandler() instanceof PullRequestBuildHandler) {
            ((PullRequestBuildHandler) trigger.getBuildHandler()).handle(pullRequest, gitHub);
          }
        }
      } finally {
        SecurityContextHolder.getContext().setAuthentication(old);
      }
    } else {
      LOGGER.warning(
          MessageFormat.format(
              "Unsupported pull request action: ''{0}''", pullRequest.getAction()));
    }
  }
Example #12
0
  /**
   * Return a list of projects which can be built
   *
   * @return
   */
  protected final List<AbstractProject<?, ?>> getProjects(String viewName) {

    List<AbstractProject<?, ?>> projects = new ArrayList<AbstractProject<?, ?>>();
    Collection<TopLevelItem> items = Jenkins.getInstance().getItems();
    View view = null;
    BulkBuilderAction bulkBuilderAction = new BulkBuilderAction();

    if (viewName != null) {
      for (View currentView : bulkBuilderAction.getViews()) {
        if (currentView.getViewName().equals(viewName)) {
          view = currentView;
        }
      }

      if (view != null) {
        items = view.getItems();
      }
    }

    for (AbstractProject<?, ?> project : Util.createSubList(items, AbstractProject.class)) {
      if (!project.isBuildable()) {
        continue;
      }
      projects.add(project);
    }

    return projects;
  }
Example #13
0
  /**
   * An attempt to generate at least semi-useful EnvVars for polling calls, based on previous build.
   * Cribbed from various places.
   */
  public static EnvVars getPollEnvironment(
      AbstractProject p, FilePath ws, Launcher launcher, TaskListener listener)
      throws IOException, InterruptedException {
    EnvVars env;

    AbstractBuild b = (AbstractBuild) p.getLastBuild();

    if (b != null) {
      Node lastBuiltOn = b.getBuiltOn();

      if (lastBuiltOn != null) {
        env = lastBuiltOn.toComputer().getEnvironment().overrideAll(b.getCharacteristicEnvVars());
      } else {
        env = new EnvVars(System.getenv());
      }

      String rootUrl = Hudson.getInstance().getRootUrl();
      if (rootUrl != null) {
        env.put("HUDSON_URL", rootUrl);
        env.put("BUILD_URL", rootUrl + b.getUrl());
        env.put("JOB_URL", rootUrl + p.getUrl());
      }

      if (!env.containsKey("HUDSON_HOME")) {
        env.put("HUDSON_HOME", Hudson.getInstance().getRootDir().getPath());
      }

      if (ws != null) {
        env.put("WORKSPACE", ws.getRemote());
      }

      p.getScm().buildEnvVars(b, env);

      StreamBuildListener buildListener =
          new StreamBuildListener((OutputStream) listener.getLogger());

      for (NodeProperty nodeProperty : Hudson.getInstance().getGlobalNodeProperties()) {
        Environment environment = nodeProperty.setUp(b, launcher, (BuildListener) buildListener);
        if (environment != null) {
          environment.buildEnvVars(env);
        }
      }

      if (lastBuiltOn != null) {
        for (NodeProperty nodeProperty : lastBuiltOn.getNodeProperties()) {
          Environment environment = nodeProperty.setUp(b, launcher, buildListener);
          if (environment != null) {
            environment.buildEnvVars(env);
          }
        }
      }

      EnvVars.resolve(env);
    } else {
      env = new EnvVars(System.getenv());
    }

    return env;
  }
 @SuppressWarnings("unused")
 public DirectoryBrowserSupport doDynamic(StaplerRequest req, StaplerResponse rsp)
     throws IOException, ServletException, InterruptedException {
   AbstractProject<?, ?> project = build.getProject();
   FilePath systemDirectory = new FilePath(AllureReportPlugin.getReportBuildDirectory(build));
   return new DirectoryBrowserSupport(
       this, systemDirectory, project.getDisplayName(), null, false);
 }
 @DataBoundConstructor
 public JobIngredient(String name, String description) {
   this.name = name;
   this.description = description;
   AbstractProject i = Jenkins.getInstance().getItemByFullName(name, AbstractProject.class);
   if (i == null) throw new IllegalArgumentException("No such job: " + name);
   this.definition = XStreamDOM.from(i.getConfigFile().getXStream(), i);
 }
    /** Makes sure that the data fields are up to date. */
    private synchronized void upToDateCheck() {
      // up to date check
      if (lastUpdated > lastChanged) return;
      lastUpdated = lastChanged + 1;

      int failCount = 0;
      int totalCount = 0;
      List<AbstractTestResultAction> individuals = new ArrayList<AbstractTestResultAction>();
      List<AbstractProject> didntRun = new ArrayList<AbstractProject>();
      List<AbstractProject> noFingerprints = new ArrayList<AbstractProject>();
      for (AbstractProject job : getJobs()) {
        RangeSet rs = owner.getDownstreamRelationship(job);
        if (rs.isEmpty()) {
          // is this job expected to produce a test result?
          Run b;
          if (includeFailedBuilds) {
            b = job.getLastBuild();
          } else {
            b = job.getLastSuccessfulBuild();
          }
          if (b != null && b.getAction(AbstractTestResultAction.class) != null) {
            if (b.getAction(FingerprintAction.class) != null) {
              didntRun.add(job);
            } else {
              noFingerprints.add(job);
            }
          }
        } else {
          for (int n : rs.listNumbersReverse()) {
            Run b = job.getBuildByNumber(n);
            if (b == null) continue;
            Result targetResult;
            if (includeFailedBuilds) {
              targetResult = Result.FAILURE;
            } else {
              targetResult = Result.UNSTABLE;
            }

            if (b.isBuilding() || b.getResult().isWorseThan(targetResult))
              continue; // don't count them

            for (AbstractTestResultAction ta : b.getActions(AbstractTestResultAction.class)) {
              failCount += ta.getFailCount();
              totalCount += ta.getTotalCount();
              individuals.add(ta);
            }
            break;
          }
        }
      }

      this.failCount = failCount;
      this.totalCount = totalCount;
      this.individuals = individuals;
      this.didntRun = didntRun;
      this.noFingerprints = noFingerprints;
    }
Example #17
0
  /** Invoked to actually tag the workspace. */
  public synchronized void doSubmit(StaplerRequest req, StaplerResponse rsp)
      throws IOException, ServletException {
    build.checkPermission(getPermission());

    Map<AbstractBuild, String> tagSet = new HashMap<AbstractBuild, String>();

    String name = fixNull(req.getParameter("name")).trim();
    String reason = isInvalidTag(name);
    if (reason != null) {
      sendError(reason, req, rsp);
      return;
    }

    tagSet.put(build, name);

    if (req.getParameter("upstream") != null) {
      // tag all upstream builds
      Enumeration e = req.getParameterNames();
      Map<AbstractProject, Integer> upstreams =
          build.getTransitiveUpstreamBuilds(); // TODO: define them at AbstractBuild level

      while (e.hasMoreElements()) {
        String upName = (String) e.nextElement();
        if (!upName.startsWith("upstream.")) {
          continue;
        }

        String tag = fixNull(req.getParameter(upName)).trim();
        reason = isInvalidTag(tag);
        if (reason != null) {
          sendError(
              hudson.scm.cvs.Messages.CVSSCM_NoValidTagNameGivenFor(upName, reason), req, rsp);
          return;
        }

        upName = upName.substring(9); // trim off 'upstream.'
        AbstractProject p = Hudson.getInstance().getItemByFullName(upName, AbstractProject.class);
        if (p == null) {
          sendError(hudson.scm.cvs.Messages.CVSSCM_NoSuchJobExists(upName), req, rsp);
          return;
        }

        Integer buildNum = upstreams.get(p);
        if (buildNum == null) {
          sendError(hudson.scm.cvs.Messages.CVSSCM_NoUpstreamBuildFound(upName), req, rsp);
          return;
        }

        Run build = p.getBuildByNumber(buildNum);
        tagSet.put((AbstractBuild) build, tag);
      }
    }

    new TagWorkerThread(this, tagSet).start();

    doIndex(req, rsp);
  }
 /**
  * Determines whether any of the upstream project are either building or in the queue.
  *
  * <p>This means eventually there will be an automatic triggering of the given project (provided
  * that all builds went smoothly.)
  *
  * @param downstreamProject The AbstractProject we want to build.
  * @param excludeProject An AbstractProject to exclude - if we see this in the transitive
  *     dependencies, we're not going to bother checking to see if it's building. For example,
  *     pass the current parent project to be sure that it will be ignored when looking for
  *     building dependencies.
  * @return True if any upstream projects are building or in queue, false otherwise.
  */
 @SuppressWarnings("rawtypes")
 private boolean areUpstreamsBuilding(
     AbstractProject<?, ?> downstreamProject, AbstractProject<?, ?> excludeProject) {
   DependencyGraph graph = Jenkins.getInstance().getDependencyGraph();
   Set<AbstractProject> tups = graph.getTransitiveUpstream(downstreamProject);
   for (AbstractProject tup : tups) {
     if (tup != excludeProject && (tup.isBuilding() || tup.isInQueue())) return true;
   }
   return false;
 }
 /**
  * Gets the RoundhouseAction as the project action. This is applicable for each job and only when
  * there's at least one build in the job.
  *
  * @param project the project
  * @return the project action
  */
 @Override
 public final Action getProjectAction(final AbstractProject<?, ?> project) {
   Action action = null;
   if (project.getLastBuild() != null) {
     Style style = Style.get(project.getLastBuild().getResult());
     String fact = factGenerator.random();
     action = new RoundhouseAction(style, fact);
   }
   return action;
 }
  private PermalinkStorage getStorage(final AbstractProject<?, ?> project) throws IOException {

    PermalinkStorage storage = project.getProperty(PermalinkStorage.class);
    if (storage == null) {

      storage = new PermalinkStorage();
      project.addProperty(storage);
    }

    return storage;
  }
  @Test
  public void testNoWikiLinkToAnnotate() {
    AbstractBuild build = mock(AbstractBuild.class);
    AbstractProject<?, ?> project = mock(AbstractProject.class);
    when(project.getProperty(CodePlexProjectProperty.class))
        .thenReturn(new CodePlexProjectProperty("theproject"));
    when(build.getProject()).thenReturn(project);

    CodePlexChangeLogAnnotator annotator = new CodePlexChangeLogAnnotator();
    MarkupText markupText = new MarkupText("Ordinary commit message without wiki link.");
    annotator.annotate(build, null, markupText);
    assertEquals("Ordinary commit message without wiki link.", markupText.toString());
  }
 /**
  * {@inheritDoc}
  *
  * <p>This parameter also includes the Jenkins project and build objects in the Groovy variables
  * map. It means that you can use these two in your code for rendering the parameter.
  */
 @Override
 public Map<Object, Object> getParameters() {
   Map<Object, Object> parameters = super.getParameters();
   final AbstractProject<?, ?> project = ((DescriptorImpl) getDescriptor()).getProject();
   if (project != null) {
     parameters.put(JENKINS_PROJECT_VARIABLE_NAME, project);
     AbstractBuild<?, ?> build = project.getLastBuild();
     if (build != null && build.getHasArtifacts()) {
       parameters.put(JENKINS_BUILD_VARIABLE_NAME, build);
     }
   }
   return parameters;
 }
Example #23
0
 public FormValidation doCheckIncludes(
     @AncestorInPath AbstractProject project, @QueryParameter String value)
     throws IOException, InterruptedException {
   if (project.getSomeWorkspace() != null) {
     String msg = project.getSomeWorkspace().validateAntFileMask(value);
     if (msg != null) {
       return FormValidation.error(msg);
     }
     return FormValidation.ok();
   } else {
     return FormValidation.warning(Messages.noworkspace());
   }
 }
 @SuppressWarnings("unchecked")
 @Override
 public void postClone(AbstractProject implementationProject) {
   try {
     if (cached != null) {
       // Removed from template = removed from all impls
       if (implementationProject.removeProperty(cached.getClass()) != null) {
         implementationProject.addProperty(cached);
       }
     }
   } catch (IOException e) {
     Throwables.propagate(e);
   }
 }
  @Test
  public void assertWorkItemInBracketsIsAnnotated() {
    AbstractBuild build = mock(AbstractBuild.class);
    AbstractProject<?, ?> project = mock(AbstractProject.class);
    when(project.getProperty(CodePlexProjectProperty.class))
        .thenReturn(new CodePlexProjectProperty("theproject"));
    when(build.getProject()).thenReturn(project);

    CodePlexChangeLogAnnotator annotator = new CodePlexChangeLogAnnotator();
    MarkupText markupText = new MarkupText("Message with [workitem: 12]. Yes a link.");
    annotator.annotate(build, null, markupText);
    assertEquals(
        "Message with <a href='http://www.codeplex.com/theproject/WorkItem/View.aspx?WorkItemId=12'>[workitem: 12]</a>. Yes a link.",
        markupText.toString());
  }
  @Test
  public void assertWikiKeyWordIsAnnotated() {
    AbstractBuild build = mock(AbstractBuild.class);
    AbstractProject<?, ?> project = mock(AbstractProject.class);
    when(project.getProperty(CodePlexProjectProperty.class))
        .thenReturn(new CodePlexProjectProperty("theproject"));
    when(build.getProject()).thenReturn(project);

    CodePlexChangeLogAnnotator annotator = new CodePlexChangeLogAnnotator();
    MarkupText markupText = new MarkupText("Message with wiki:WikiLink. Yes a link.");
    annotator.annotate(build, null, markupText);
    assertEquals(
        "Message with <a href='http://www.codeplex.com/theproject/Wiki/View.aspx?title=WikiLink'>wiki:WikiLink</a>. Yes a link.",
        markupText.toString());
  }
    public FormValidation doCheck(
        @AncestorInPath AbstractProject project, @QueryParameter String value) {
      // Require CONFIGURE permission on this project
      if (!project.hasPermission(Item.CONFIGURE)) return FormValidation.ok();

      for (String name : Util.tokenize(fixNull(value), ",")) {
        name = name.trim();
        if (Jenkins.getInstance().getItem(name, project) == null)
          return FormValidation.error(
              hudson.tasks.Messages.BuildTrigger_NoSuchProject(
                  name, AbstractProject.findNearest(name).getName()));
      }

      return FormValidation.ok();
    }
    public TestResultAction(String jobs, boolean includeFailedBuilds, AbstractBuild<?, ?> owner) {
      super(owner);
      this.includeFailedBuilds = includeFailedBuilds;

      if (jobs == null) {
        // resolve null as the transitive downstream jobs
        StringBuilder buf = new StringBuilder();
        for (AbstractProject p : getProject().getTransitiveDownstreamProjects()) {
          if (buf.length() > 0) buf.append(',');
          buf.append(p.getFullName());
        }
        jobs = buf.toString();
      }
      this.jobs = jobs;
    }
  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 static LockableResourcesStruct requiredResources(AbstractProject<?, ?> project) {
   RequiredResourcesProperty property = project.getProperty(RequiredResourcesProperty.class);
   if (property != null) {
     return new LockableResourcesStruct(property);
   }
   return null;
 }