Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Checks for queue item #1

Merged
merged 5 commits into from
Aug 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package io.jenkins.plugins.checks;

import edu.umd.cs.findbugs.annotations.NonNull;

import hudson.Extension;
import hudson.model.Queue;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.TaskListener;

import hudson.model.listeners.RunListener;
import hudson.model.queue.QueueListener;
import io.jenkins.plugins.checks.api.ChecksConclusion;
import io.jenkins.plugins.checks.api.ChecksDetails.ChecksDetailsBuilder;
import io.jenkins.plugins.checks.api.ChecksPublisher;
import io.jenkins.plugins.checks.api.ChecksPublisherFactory;
import io.jenkins.plugins.checks.api.ChecksStatus;

/**
* A publisher which publishes different statuses through the checks API based on the stage of the {@link Queue.Item}
* or {@link Run}.
*/
public class BuildStatusChecksPublisher {
private static final String CHECKS_NAME = "Jenkins";

private static void publish(final ChecksPublisher publisher, final ChecksStatus status,
final ChecksConclusion conclusion) {
publisher.publish(new ChecksDetailsBuilder()
.withName(CHECKS_NAME)
.withStatus(status)
.withConclusion(conclusion)
.build());
}

/**
* {@inheritDoc}
*
* Listens to the queue and publishes checks in "queued" state for entering items.
*/
@Extension
public static class JobScheduledListener extends QueueListener {
/**
* {@inheritDoc}
*
* When a job enters queue, creates the check on "queued".
*/
@Override
public void onEnterWaiting(Queue.WaitingItem wi) {
publish(ChecksPublisherFactory.fromItem(wi), ChecksStatus.QUEUED, ChecksConclusion.NONE);
}
}

/**
* {@inheritDoc}
*
* Listens to the run and publishes checks for started and completed run.
*/
@Extension
public static class JobStartedListener extends RunListener<Run<?, ?>> {
/**
* {@inheritDoc}
*
* When a job starts, updates the check to "in progress".
*/
@Override
public void onStarted(final Run run, final TaskListener listener) {
publish(ChecksPublisherFactory.fromRun(run), ChecksStatus.IN_PROGRESS, ChecksConclusion.NONE);
}

/**
* {@inheritDoc}
*
* When a job completes, completes the check.
*/
@Override
public void onCompleted(final Run run, @NonNull final TaskListener listener) {
publish(ChecksPublisherFactory.fromRun(run), ChecksStatus.COMPLETED, extractConclusion(run));
}

private ChecksConclusion extractConclusion(final Run<?, ?> run) {
Result result = run.getResult();
if (result == null) {
throw new IllegalStateException("No result when the run completes, run: " + run.toString());
}

if (result.isBetterOrEqualTo(Result.SUCCESS)) {
return ChecksConclusion.SUCCESS;
}
else if (result.isBetterOrEqualTo(Result.UNSTABLE)) {
return ChecksConclusion.NEUTRAL;
}
else if (result.isBetterOrEqualTo(Result.FAILURE)) {
return ChecksConclusion.FAILURE;
}
else if (result.isBetterOrEqualTo(Result.NOT_BUILT)) {
return ChecksConclusion.SKIPPED;
}
else if (result.isBetterOrEqualTo(Result.ABORTED)) {
return ChecksConclusion.CANCELED;
}
else {
throw new IllegalStateException("Unsupported run result: " + result);
}
}
}
}
67 changes: 0 additions & 67 deletions src/main/java/io/jenkins/plugins/checks/JobListener.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.List;
import java.util.Optional;

import hudson.model.Queue;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.Beta;
import hudson.ExtensionPoint;
Expand All @@ -25,6 +26,15 @@ public abstract class ChecksPublisherFactory implements ExtensionPoint {
*/
protected abstract Optional<ChecksPublisher> createPublisher(Run<?, ?> run);

/**
* Creates a {@link ChecksPublisher} according to the {@link hudson.scm.SCM} used by the {@link Run}.
*
* @param item
* an item in the queue
* @return the created {@link ChecksPublisher}
*/
protected abstract Optional<ChecksPublisher> createPublisher(Queue.Item item);

/**
* Returns a suitable publisher for the run.
*
Expand All @@ -41,6 +51,22 @@ public static ChecksPublisher fromRun(final Run<?, ?> run) {
.orElse(new NullChecksPublisher());
}

/**
* Returns a suitable publisher for the waiting item.
*
* @param item
* an item in the queue
* @return a publisher suitable for the run
*/
public static ChecksPublisher fromItem(Queue.Item item) {
return findAllPublisherFactories().stream()
.map(factory -> factory.createPublisher(item))
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst()
.orElse(new NullChecksPublisher());
}

private static List<ChecksPublisherFactory> findAllPublisherFactories() {
return new JenkinsFacade().getExtensionsFor(ChecksPublisherFactory.class);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@

import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.Queue;
import hudson.model.Run;
import io.jenkins.plugins.checks.api.ChecksPublisher.NullChecksPublisher;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;

import java.util.Calendar;
import java.util.Collections;

import static org.assertj.core.api.Assertions.assertThat;

/**
Expand All @@ -21,17 +25,32 @@ public class ChecksPublisherFactoryITest {
public JenkinsRule rule = new JenkinsRule();

/**
* A {@link NullChecksPublisher} should be returned when creating the {@link ChecksPublisher} with a {@link Run}
* of {@link FreeStyleProject}.
* A {@link NullChecksPublisher} should be returned when creating the {@link ChecksPublisher} for a {@link Run} but
* no implementation for the checks api is provided.
*
* @throws Exception if fails to freestyle project or build
* @throws Exception if fails to create freestyle project or build
*/
@Test
public void shouldReturnNullChecksPublisherWhenUseFreestyleRun() throws Exception {
public void shouldReturnNullChecksPublisherForRunWhenNoImplementationIsProvided() throws Exception {
FreeStyleProject job = rule.createFreeStyleProject();
FreeStyleBuild run = rule.buildAndAssertSuccess(job);

ChecksPublisher publisher = ChecksPublisherFactory.fromRun(run);
assertThat(publisher).isInstanceOf(NullChecksPublisher.class);
}

/**
* A {@link NullChecksPublisher} should be returned when creating the {@link ChecksPublisher} for an
* {@link Queue.Item} but no implementation for the checks api is provided.
*
* @throws Exception if fails to create freestyle project
*/
@Test
public void shouldReturnNullChecksPublisherForQueueItemWhenNoImplementationIsProvided() throws Exception {
FreeStyleProject job = rule.createFreeStyleProject();
Queue.Item item = new Queue.WaitingItem(Calendar.getInstance(), job, Collections.emptyList());

ChecksPublisher publisher = ChecksPublisherFactory.fromItem(item);
assertThat(publisher).isInstanceOf(NullChecksPublisher.class);
}
}