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

org.aerogear.digger.client.services.BuildService Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2016-2017 Red Hat, Inc, and individual contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.aerogear.digger.client.services;

import com.offbytwo.jenkins.JenkinsServer;
import com.offbytwo.jenkins.model.*;
import org.aerogear.digger.client.DiggerClient;
import org.aerogear.digger.client.model.BuildTriggerStatus;
import org.aerogear.digger.client.model.LogStreamingOptions;
import org.aerogear.digger.client.util.DiggerClientException;
import org.apache.commons.collections4.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * Provides functionality to trigger a build.
 **/
public class BuildService {

    private static final Logger LOG = LoggerFactory.getLogger(BuildService.class);

    /**
     * Default value of {@link #firstCheckDelay}
     */
    public static final long DEFAULT_FIRST_CHECK_DELAY = 5 * 1000L;

    /**
     * Default value of {@link #pollPeriod}
     */
    public static final long DEFAULT_POLL_PERIOD = 2 * 1000L;


    private long firstCheckDelay;
    private long pollPeriod;

    /**
     * @param firstCheckDelay how long should we wait (in milliseconds) before we start checking the queue item status
     * @param pollPeriod      how long should we wait (in milliseconds) before checking the queue item status for next time
     */
    public BuildService(long firstCheckDelay, long pollPeriod) {
        this.firstCheckDelay = firstCheckDelay;
        this.pollPeriod = pollPeriod;
    }


    /**
     * Get build logs for specific job and build number
     *
     * @param jobName     name of the job
     * @param buildNumber job build number
     * @return String with file contents that can be saved or piped to socket
     * @throws DiggerClientException when problem with fetching artifacts from jenkins
     */
    public String getBuildLogs(JenkinsServer jenkins, String jobName, int buildNumber) throws DiggerClientException, IOException {
        Build build = this.getBuild(jenkins, jobName, buildNumber);
        BuildWithDetails buildWithDetails = build.details();
        return buildWithDetails.getConsoleOutputText();
    }

    /**
     * Returns the build history for a job. As reported by {@link JobWithDetails#getBuilds()} it will return max 100 most-recent builds.
     * 

* Please note that this approach will take some time since we first fetch the builds in 1 call, then fetch build details in 1 call per build. * * @param jenkins Jenkins server client * @param jobName name of the job * @return the build history * @throws DiggerClientException if connection problems occur */ public List getBuildHistory(JenkinsServer jenkins, String jobName) throws DiggerClientException { final JobWithDetails job; try { job = jenkins.getJob(jobName); if (job == null) { LOG.error("Cannot fetch job from jenkins {0}", jobName); throw new DiggerClientException("Cannot fetch job from jenkins"); } final List builds = job.getBuilds(); final List returnValue = new ArrayList(); for (Build build : builds) { try { returnValue.add(build.details()); } catch (IOException e) { LOG.error("Error while fetching the details for job {} with build number", jobName, build.getNumber(), e); // re-raise it so the the outer block catches it and creates a DiggerClientException out of it throw e; } } return returnValue; } catch (IOException e) { LOG.error("Problem when getting the build history for job {0}", jobName, e); throw new DiggerClientException(e); } } /** * * @param jenkinsServer Jenkins server client * @param jobName name of the job * @param params build parameters to override defaults in the job * @return The QueueReference * @throws IOException if connection problems occur during connecting to Jenkins * @throws InterruptedException if a problem occurs during sleeping between checks */ public BuildTriggerStatus triggerBuild(JenkinsServer jenkinsServer, String jobName, Map params) throws IOException, InterruptedException { LOG.debug("Getting QueueReference for Job '{}'", jobName); QueueReference queueReference = null; JobWithDetails job = jenkinsServer.getJob(jobName); if (job == null) { LOG.debug("Unable to find job for name '{}'", jobName); throw new IllegalArgumentException("Unable to find job for name '" + jobName + "'"); } else { queueReference = MapUtils.isEmpty(params) ? job.build() : job.build(params); if (queueReference == null) { // this is probably an implementation problem we have here LOG.debug("Queue reference cannot be null!"); throw new IllegalStateException("Queue reference cannot be null!"); } LOG.debug("Queue item reference: {}", queueReference.getQueueItemUrlPart()); return new BuildTriggerStatus(BuildTriggerStatus.State.TRIGGERED, job.getNextBuildNumber(), queueReference); } } /** * See the documentation in {@link DiggerClient#build(String, long, Map)} * * @param jenkinsServer Jenkins server client * @param jobName name of the job * @param timeout timeout * @param params build parameters to override defaults in the job * @return the build status * @throws IOException if connection problems occur during connecting to Jenkins * @throws InterruptedException if a problem occurs during sleeping between checks * @see DiggerClient#build(String, long, Map) */ public BuildTriggerStatus pollBuild(JenkinsServer jenkinsServer, String jobName, QueueReference queueReference, long timeout, Map params) throws IOException, InterruptedException { final long whenToTimeout = System.currentTimeMillis() + timeout; LOG.debug("Going to build job with name: {}", jobName); LOG.debug("Going to timeout in {} msecs if build didn't start executing", timeout); LOG.debug("Build triggered; queue item reference: {}", queueReference.getQueueItemUrlPart()); // wait for N seconds, then fetch the queue item. // do it until we have an executable. // we would have an executable when the build leaves queue and starts building. LOG.debug("Going to sleep {} msecs", firstCheckDelay); Thread.sleep(firstCheckDelay); QueueItem queueItem; while (true) { queueItem = jenkinsServer.getQueueItem(queueReference); LOG.debug("Queue item : {}", queueItem); if (queueItem == null) { // this is probably an implementation problem we have here LOG.debug("Queue item cannot be null!"); throw new IllegalStateException("Queue item cannot be null!"); } LOG.debug("Build item cancelled:{}, blocked:{}, buildable:{}, stuck:{}", queueItem.isCancelled(), queueItem.isBlocked(), queueItem.isBuildable(), queueItem.isStuck()); if (queueItem.isCancelled()) { LOG.debug("Queue item is cancelled. Returning CANCELLED_IN_QUEUE"); return new BuildTriggerStatus(BuildTriggerStatus.State.CANCELLED_IN_QUEUE, -1, queueReference); } else if (queueItem.isStuck()) { LOG.debug("Queue item is stuck. Returning STUCK_IN_QUEUE"); return new BuildTriggerStatus(BuildTriggerStatus.State.STUCK_IN_QUEUE, -1, queueReference); } // do not return -1 if blocked. // we will wait until it is unblocked. final Executable executable = queueItem.getExecutable(); if (executable != null) { LOG.debug("Build has an executable. Returning build number: {}", executable.getNumber()); return new BuildTriggerStatus(BuildTriggerStatus.State.STARTED_BUILDING, executable.getNumber().intValue(), queueReference); } else { LOG.debug("Build did not start executing yet."); if (whenToTimeout > System.currentTimeMillis()) { LOG.debug("Timeout period has not exceeded yet. Sleeping for {} msecs", pollPeriod); Thread.sleep(pollPeriod); } else { LOG.debug("Timeout period has exceeded. Returning TIMED_OUT."); return new BuildTriggerStatus(BuildTriggerStatus.State.TIMED_OUT, -1, queueReference); } } } } /** * See the documentation in {@link DiggerClient#build(String, long)} * * @param jenkinsServer Jenkins server client * @param jobName name of the job * @param timeout timeout * @return the build status * @throws IOException if connection problems occur during connecting to Jenkins * @throws InterruptedException if a problem occurs during sleeping between checks * @see DiggerClient#build(String, long) */ public BuildTriggerStatus build(JenkinsServer jenkinsServer, String jobName, long timeout) throws IOException, InterruptedException { BuildTriggerStatus buildTriggerStatus = this.triggerBuild(jenkinsServer, jobName, null); return this.pollBuild(jenkinsServer, jobName, buildTriggerStatus.getQueueReference(), timeout, null); } /** * Retrieve a build from a specific job * * @param jenkins the jenkins instance * @param jobName the name of the job * @param buildNumber the build number * @return {@link Build} * @throws DiggerClientException */ public Build getBuild(JenkinsServer jenkins, String jobName, int buildNumber) throws DiggerClientException { try { JobWithDetails job = jenkins.getJob(jobName); if (job == null) { LOG.error("Cannot fetch job from jenkins {0}", jobName); throw new DiggerClientException("Cannot fetch job from jenkins"); } Build build = job.getBuildByNumber(buildNumber); return build; } catch (IOException e) { LOG.error("Problem when fetching logs for {0} {1}", jobName, buildNumber, e); throw new DiggerClientException(e); } } /** * Get the build details of a job * * @param jenkins the jenkins instance * @param jobName the name of the job * @param buildNumber the build number * @return {@link BuildWithDetails} * @throws DiggerClientException */ public BuildWithDetails getBuildDetails(JenkinsServer jenkins, String jobName, int buildNumber) throws DiggerClientException, IOException { Build build = this.getBuild(jenkins, jobName, buildNumber); BuildWithDetails buildWithDetails = build.details(); return buildWithDetails; } /** * Cancel a build * @param jenkins the jenkins instance * @param jobName the name of the job * @param buildNumber the build number * @return {@link BuildWithDetails} * @throws DiggerClientException * @throws IOException */ public BuildWithDetails cancelBuild(JenkinsServer jenkins, String jobName, int buildNumber) throws DiggerClientException, IOException { Build build = this.getBuild(jenkins, jobName, buildNumber); build.Stop(); BuildWithDetails buildWithDetails = build.details(); return buildWithDetails; } /** * Start streaming the logs of the given build. * See {@link DiggerClient#streamLogs(String, int, LogStreamingOptions)} */ public void streamBuildLogs(JenkinsServer jenkins, String jobName, int buildNumber, LogStreamingOptions options) throws DiggerClientException, IOException, InterruptedException { BuildWithDetails buildDetails = this.getBuildDetails(jenkins, jobName, buildNumber); buildDetails.streamConsoleOutput(options.getStreamListener(), options.getPollingInterval(), options.getPollingTimeout()); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy