Package com.etsy.jenkins.cli

Source Code of com.etsy.jenkins.cli.BuildMasterCommand$CLIEnvironmentContributor

package com.etsy.jenkins.cli;

import com.etsy.jenkins.MasterProject;
import com.etsy.jenkins.SubProjectsAction;
import com.etsy.jenkins.SubProjectsJobProperty;
import com.etsy.jenkins.cli.handlers.MasterProjectOptionHandler;
import com.etsy.jenkins.finder.BuildFinder;
import com.etsy.jenkins.finder.ProjectFinder;

import hudson.AbortException;
import hudson.EnvVars;
import hudson.Extension;
import hudson.cli.CLICommand;
import hudson.console.HyperlinkNote;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Cause;
import hudson.model.EnvironmentContributor;
import hudson.model.Hudson;
import hudson.model.Item;
import hudson.model.ParametersAction;
import hudson.model.ParameterValue;
import hudson.model.ParameterDefinition;
import hudson.model.ParametersDefinitionProperty;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.model.TopLevelItem;
import hudson.model.User;
import hudson.util.EditDistance;

import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
import org.kohsuke.stapler.export.Exported;

import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Inject;

import java.io.PrintStream;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;

@Extension
public class BuildMasterCommand extends CLICommand {

  @Inject static Hudson hudson;
  @Inject static BuildFinder buildFinder;
  @Inject static ProjectFinder projectFinder;

  @Override
  public String getShortDescription() {
    return "Builds a try job,"
        + " and optionally waits until its completion.";
  }

  @Argument(
      handler=MasterProjectOptionHandler.class,
      metaVar="MASTER_JOB",
      usage="Name of the job to build",
      required=true)
  public MasterProject job;

  @Argument(
      metaVar="SUB_JOBS",
      usage="List of sub jobs to execute. If Master Project plugin is"
          + " installed and the JOB is a Master Project.",
      index=1,
      multiValued=true)
  public List<String> subJobs = Lists.<String>newArrayList();

  @Option(
      name="-s",
      usage="Wait until the completion/abortion of the command.")
  public boolean sync = false;

  @Option(
      name="-p",
      usage="Specify the build parameters in the key=value format.")
  public Map<String, String> parameters = Maps.<String, String>newHashMap();

  @Override
  protected int run() throws Exception {
    job.checkPermission(Item.BUILD);

    SubProjectsAction sp = null;
    SubProjectsJobProperty spjp = (SubProjectsJobProperty)
        job.getProperty(SubProjectsJobProperty.class);
    if (!subJobs.isEmpty()) {
      if (spjp == null) {
        throw new AbortException(
            String.format(
                "%s does not allow sub-job selection but sub-jobs were"
                + " specified.",
                job.getDisplayName()));
      }
      Set<String> subProjects = Sets.<String>newHashSet();
      Set<String> excludeProjects = Sets.<String>newHashSet();
      for (String subJob : subJobs) {
        boolean exclude = false;
        if  (subJob.charAt(0) == '-') {
            exclude = true;
            subJob = subJob.substring(1, subJob.length());
        }
        AbstractProject project = projectFinder.findProject(subJob);
        if (project == null) {
          throw new AbortException(
            String.format(
                "Project does not exist: %s",
                subJob));
        }
        if (!job.contains((TopLevelItem) project)) {
          throw new AbortException(
              String.format(
                  "%s does not exist in Master Project: %s",
                  subJob,
                  job.getDisplayName()));
        }
        if (exclude) {
          excludeProjects.add(subJob);
        } else {
          subProjects.add(subJob);
        }
      }
      sp = new SubProjectsAction(subProjects, excludeProjects);
    } else if (spjp != null) {
      stdout.println(
          String.format(
              "Executing DEFAULT sub-jobs: %s",
              spjp.getDefaultSubProjectsString()));
    }

    ParametersAction a = null;
    if (!parameters.isEmpty()) {
      ParametersDefinitionProperty pdp =
          job.getProperty(ParametersDefinitionProperty.class);
      if (pdp == null) {
        throw new AbortException(
            String.format(
                "%s is not parameterized but the -p option was specified.",
                job.getDisplayName()));
      }

      List<ParameterValue> values = Lists.<ParameterValue>newArrayList();

      for (Map.Entry<String, String> e : parameters.entrySet()) {
        String name = e.getKey();
        ParameterDefinition pd = pdp.getParameterDefinition(name);
        if (pd == null) {
          throw new AbortException(
              String.format(
                  "\'%s\' is not a valid parameter. Did you mean %s?",
                  name,
                  EditDistance.findNearest(
                      name,
                      pdp.getParameterDefinitionNames())));
         }
         values.add(pd.createValue(this, e.getValue()));
       }

       // handle missing parameters by adding as default values ISSUE JENKINS-7162
       for (ParameterDefinition pd :  pdp.getParameterDefinitions()) {
         if (parameters.containsKey(pd.getName()))
           continue;

         // not passed in use default
         values.add(pd.getDefaultParameterValue());
       }

       a = new ParametersAction(values);
     }

     String user = Hudson.getAuthentication().getName();

     CLICause cause = new CLICause(user, a, sp);
     Future<? extends AbstractBuild> f =
         job.scheduleBuild2(0, cause, a, sp);

     AbstractBuild build = null;
     do {
       build = buildFinder.findBuild(job, cause);
       stdout.println(
           String.format("......... %s ( pending )", job.getDisplayName()));
       rest();
     } while(build == null);

     stdout.println(
         String.format("......... %s ( %s%s )",
          job.getDisplayName(),
          hudson.getRootUrl(),
          build.getUrl()));
     build.setDescription("<h2>" + cause.getUserName() + "</h2>");

     if (!sync) return 0;

     AbstractBuild b = f.get()// wait for completion
     stdout.println(
         String.format(
             "Completed %s : %s",
             b.getFullDisplayName(),
             b.getResult()));
     return b.getResult().ordinal;
  }

  private void rest() {
    try {
      Thread.sleep(7000L);
    } catch (InterruptedException ignore) {}
  }

  @Override
  protected void printUsageSummary(PrintStream stderr) {
    stderr.println(
        "Starts a master job, and optionally waits for a completion.\n\n"
        + "Aside from general scripting use, this command can be\n"
        + "used to invoke another job from within a build of one job.\n"
        + "With the -s option, this command changes the exit code based on\n"
        + "the outcome of the build (exit code 0 indicates success.)\n");
  }

  public static class CLICause extends Cause {

    private final String user;
    private final ParametersAction parameters;
    private final SubProjectsAction subProjects;

    public CLICause(
        String user,
        ParametersAction parameters,
        SubProjectsAction subProjects) {
      this.user = user;
      this.parameters = parameters;
      this.subProjects = subProjects;
    }

    @Exported(visibility=3)
    public String getUserName() {
      User u = User.get(user, false);
      return (u == null) ? user : u.getDisplayName();
    }

    @Exported(visibility=3)
    public String getUserUrl() {
      User u = User.get(user, false);
      if (u == null) {
        u = User.getUnknown();
      }
      return u.getAbsoluteUrl();
    }

    @Override
    public String getShortDescription() {
      return "Started by command line";
    }

    @Override
    public void print(TaskListener listener) {
        listener.getLogger().println(String.format(
          "Started by command line for %s\n",
           HyperlinkNote.encodeTo(getUserUrl(), getUserName())));
    }

    @Override
    public boolean equals(Object o) {
      if (!(o instanceof CLICause)) {
        return false;
      }
      CLICause other = (CLICause) o;
      return Objects.equal(this.user, other.user)
          && Objects.equal(this.parameters, other.parameters)
          && Objects.equal(this.subProjects, other.subProjects);
    }

    @Override
    public int hashCode() {
      return Objects.hashCode(this.user, this.parameters, this.subProjects);
    }
  }

  @Extension
  public static class CLIEnvironmentContributor
  extends EnvironmentContributor {

    @Override
    public void buildEnvironmentFor(Run r, EnvVars envs, TaskListener listener) {
      CLICause cause = (CLICause) r.getCause(CLICause.class);
      if (cause == null) return;
      envs.put("TRIGGERING_USER", cause.getUserName());
    }
  }
}
TOP

Related Classes of com.etsy.jenkins.cli.BuildMasterCommand$CLIEnvironmentContributor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.