Skip to content

Commit

Permalink
Merge pull request #34 from jenkinsci/validate-github-scm-source
Browse files Browse the repository at this point in the history
Validate GitHub scm source
  • Loading branch information
XiongKezhi authored Aug 25, 2020
2 parents 37de36b + 92ce6e0 commit a0c5db0
Show file tree
Hide file tree
Showing 9 changed files with 401 additions and 278 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package io.jenkins.plugins.checks.github;

import java.util.Optional;

import org.apache.commons.lang3.StringUtils;

import edu.hm.hafner.util.FilteredLog;
import edu.umd.cs.findbugs.annotations.CheckForNull;

import org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials;
import hudson.model.Job;
import org.apache.commons.lang3.StringUtils;
import org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials;

import io.jenkins.plugins.util.PluginLogger;
import java.util.Optional;

/**
* Base class for a context that publishes GitHub checks.
Expand All @@ -25,19 +22,10 @@ abstract class GitHubChecksContext {
this.scmFacade = scmFacade;
}

/**
* Returns the Jenkins job.
*
* @return job for which the checks will be based on
*/
public Job<?, ?> getJob() {
return job;
}

/**
* Returns the commit sha of the run.
*
* @return the commit sha of the run or null
* @return the commit sha of the run
*/
public abstract String getHeadSha();

Expand All @@ -50,22 +38,26 @@ abstract class GitHubChecksContext {
public abstract String getRepository();

/**
* Returns the credentials to access the remote GitHub repository.
* Returns whether the context is valid (with all properties functional) to use.
*
* @return the credentials or null
* @param logger
* the filtered logger
* @return whether the context is valid to use
*/
public GitHubAppCredentials getCredentials() {
String credentialsId = getCredentialsId();
if (credentialsId == null) {
throw new IllegalStateException("No credentials available for job: " + getJob().getName());
}

return getGitHubAppCredentials(credentialsId);
}
public abstract boolean isValid(FilteredLog logger);

@CheckForNull
protected abstract String getCredentialsId();

/**
* Returns the credentials to access the remote GitHub repository.
*
* @return the credentials
*/
public GitHubAppCredentials getCredentials() {
return getGitHubAppCredentials(StringUtils.defaultIfEmpty(getCredentialsId(), ""));
}

/**
* Returns the URL of the run's summary page, e.g. https://ci.jenkins.io/job/Core/job/jenkins/job/master/2000/.
*
Expand All @@ -75,25 +67,19 @@ public String getURL() {
return url;
}

SCMFacade getScmFacade() {
return scmFacade;
protected Job<?, ?> getJob() {
return job;
}

protected GitHubAppCredentials getGitHubAppCredentials(final String credentialsId) {
Optional<GitHubAppCredentials> foundCredentials = findGitHubAppCredentials(credentialsId);
if (!foundCredentials.isPresent()) {
throw new IllegalStateException("No GitHub APP credentials available for job: " + getJob().getName());
}

return foundCredentials.get();
protected SCMFacade getScmFacade() {
return scmFacade;
}

Optional<GitHubAppCredentials> findGitHubAppCredentials(final String credentialsId) {
return getScmFacade().findGitHubAppCredentials(getJob(), credentialsId);
protected GitHubAppCredentials getGitHubAppCredentials(final String credentialsId) {
return findGitHubAppCredentials(credentialsId).orElseThrow(() ->
new IllegalStateException("No GitHub APP credentials available for job: " + getJob().getName()));
}

abstract boolean isValid(PluginLogger listener);

protected boolean hasGitHubAppCredentials() {
return findGitHubAppCredentials(StringUtils.defaultIfEmpty(getCredentialsId(), "")).isPresent();
}
Expand All @@ -102,20 +88,24 @@ protected boolean hasCredentialsId() {
return StringUtils.isNoneBlank(getCredentialsId());
}

protected boolean hasValidCredentials(final PluginLogger logger) {
protected boolean hasValidCredentials(final FilteredLog logger) {
if (!hasCredentialsId()) {
logger.log("No credentials found");
logger.logError("No credentials found");

return false;
}

if (!hasGitHubAppCredentials()) {
logger.log("No GitHub app credentials found: '%s'", getCredentialsId());
logger.log("See: https://github.com/jenkinsci/github-branch-source-plugin/blob/master/docs/github-app.adoc");
logger.logError("No GitHub app credentials found: '%s'", getCredentialsId());
logger.logError("See: https://github.com/jenkinsci/github-branch-source-plugin/blob/master/docs/github-app.adoc");

return false;
}

return true;
}

private Optional<GitHubAppCredentials> findGitHubAppCredentials(final String credentialsId) {
return getScmFacade().findGitHubAppCredentials(getJob(), credentialsId);
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
package io.jenkins.plugins.checks.github;

import edu.hm.hafner.util.VisibleForTesting;
import io.jenkins.plugins.checks.api.ChecksDetails;
import io.jenkins.plugins.checks.api.ChecksPublisher;
import io.jenkins.plugins.util.PluginLogger;
import org.apache.commons.lang3.StringUtils;
import org.jenkinsci.plugins.github_branch_source.Connector;
import org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials;
import org.kohsuke.github.GHCheckRunBuilder;
import org.kohsuke.github.GitHub;

import java.io.IOException;
import java.time.Instant;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.lang3.StringUtils;

import edu.hm.hafner.util.VisibleForTesting;
import edu.umd.cs.findbugs.annotations.CheckForNull;

import org.kohsuke.github.GHCheckRunBuilder;
import org.kohsuke.github.GitHub;
import org.jenkinsci.plugins.github_branch_source.Connector;
import org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials;
import hudson.model.TaskListener;

import io.jenkins.plugins.checks.api.ChecksDetails;
import io.jenkins.plugins.checks.api.ChecksPublisher;

/**
* A publisher which publishes GitHub check runs.
*/
Expand All @@ -28,8 +24,7 @@ public class GitHubChecksPublisher extends ChecksPublisher {
private static final Logger LOGGER = Logger.getLogger(GitHubChecksPublisher.class.getName());

private final GitHubChecksContext context;
@CheckForNull
private final TaskListener listener;
private final PluginLogger logger;
private final String gitHubUrl;

/**
Expand All @@ -38,16 +33,15 @@ public class GitHubChecksPublisher extends ChecksPublisher {
* @param context
* a context which contains SCM properties
*/
public GitHubChecksPublisher(final GitHubChecksContext context, @CheckForNull final TaskListener listener) {
this(context, listener, GITHUB_URL);
public GitHubChecksPublisher(final GitHubChecksContext context, final PluginLogger logger) {
this(context, logger, GITHUB_URL);
}

GitHubChecksPublisher(final GitHubChecksContext context, @CheckForNull final TaskListener listener,
final String gitHubUrl) {
GitHubChecksPublisher(final GitHubChecksContext context, final PluginLogger logger, final String gitHubUrl) {
super();

this.context = context;
this.listener = listener;
this.logger = logger;
this.gitHubUrl = gitHubUrl;
}

Expand All @@ -66,17 +60,13 @@ public void publish(final ChecksDetails details) {

GitHubChecksDetails gitHubDetails = new GitHubChecksDetails(details);
createBuilder(gitHub, gitHubDetails).create();
if (listener != null) {
listener.getLogger().printf("GitHub check (name: %s, status: %s) has been published.%n",
gitHubDetails.getName(), gitHubDetails.getStatus());
}
logger.log("GitHub check (name: %s, status: %s) has been published.", gitHubDetails.getName(),
gitHubDetails.getStatus());
}
catch (IllegalStateException | IOException e) {
catch (IOException e) {
String message = "Failed Publishing GitHub checks: ";
LOGGER.log(Level.WARNING, (message + details).replaceAll("[\r\n]", ""), e);
if (listener != null) {
listener.getLogger().println(message + e);
}
logger.log(message + e);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,87 +1,64 @@
package io.jenkins.plugins.checks.github;

import java.util.Optional;

import org.jenkinsci.plugins.displayurlapi.DisplayURLProvider;

import edu.hm.hafner.util.FilteredLog;
import edu.hm.hafner.util.VisibleForTesting;
import io.jenkins.plugins.checks.api.ChecksPublisher;
import io.jenkins.plugins.checks.api.ChecksPublisherFactory;
import io.jenkins.plugins.util.PluginLogger;

import hudson.Extension;
import hudson.model.Job;
import hudson.model.Run;
import hudson.model.TaskListener;
import io.jenkins.plugins.checks.api.ChecksPublisher;
import io.jenkins.plugins.checks.api.ChecksPublisherFactory;
import io.jenkins.plugins.util.PluginLogger;
import org.jenkinsci.plugins.displayurlapi.DisplayURLProvider;

import java.util.Optional;

/**
* An factory which produces {@link GitHubChecksPublisher}.
*/
@Extension
public class GitHubChecksPublisherFactory extends ChecksPublisherFactory {
private final SCMFacade scmFacade;
private final DisplayURLProvider urlProvider;

/**
* Creates a new instance of {@link GitHubChecksPublisherFactory}.
*/
public GitHubChecksPublisherFactory() {
this(new SCMFacade());
this(new SCMFacade(), DisplayURLProvider.get());
}

@VisibleForTesting
GitHubChecksPublisherFactory(final SCMFacade scmFacade) {
GitHubChecksPublisherFactory(final SCMFacade scmFacade, final DisplayURLProvider urlProvider) {
super();

this.scmFacade = scmFacade;
this.urlProvider = urlProvider;
}

@Override
protected Optional<ChecksPublisher> createPublisher(final Run<?, ?> run, final TaskListener listener) {
return createPublisher(run, DisplayURLProvider.get().getRunURL(run), listener);
}

@VisibleForTesting
Optional<ChecksPublisher> createPublisher(final Run<?, ?> run, final String runURL, final TaskListener listener) {
PluginLogger logger = createLogger(getListener(listener));

GitSCMChecksContext gitSCMContext = new GitSCMChecksContext(run, runURL);
if (gitSCMContext.isValid(logger)) {
return Optional.of(new GitHubChecksPublisher(gitSCMContext, getListener(listener)));
}

return createPublisher(listener, logger, new GitHubSCMSourceChecksContext(run, runURL, scmFacade));
final String runURL = urlProvider.getRunURL(run);
return createPublisher(listener, new GitSCMChecksContext(run, runURL, scmFacade),
new GitHubSCMSourceChecksContext(run, runURL, scmFacade));
}

@Override
protected Optional<ChecksPublisher> createPublisher(final Job<?, ?> job, final TaskListener listener) {
return createPublisher(job, DisplayURLProvider.get().getJobURL(job), listener);
}

@VisibleForTesting
Optional<ChecksPublisher> createPublisher(final Job<?, ?> job, final String jobURL, final TaskListener listener) {
PluginLogger logger = createLogger(getListener(listener));

return createPublisher(listener, logger, new GitHubSCMSourceChecksContext(job, jobURL, scmFacade));
return createPublisher(listener, new GitHubSCMSourceChecksContext(job, urlProvider.getJobURL(job), scmFacade));
}

private Optional<ChecksPublisher> createPublisher(final TaskListener listener, final PluginLogger logger,
final GitHubChecksContext gitHubSCMSourceContext) {
if (gitHubSCMSourceContext.isValid(logger)) {
return Optional.of(new GitHubChecksPublisher(gitHubSCMSourceContext, getListener(listener)));
}
return Optional.empty();
}
private Optional<ChecksPublisher> createPublisher(final TaskListener listener, final GitHubChecksContext... contexts) {
FilteredLog causeLogger = new FilteredLog("Causes for no suitable publisher found: ");
PluginLogger consoleLogger = new PluginLogger(listener.getLogger(), "GitHub Checks");


private TaskListener getListener(final TaskListener taskListener) {
// FIXME: checks-API should use a Null listener
if (taskListener == null) {
return TaskListener.NULL;
for (GitHubChecksContext ctx : contexts) {
if (ctx.isValid(causeLogger)) {
return Optional.of(new GitHubChecksPublisher(ctx, consoleLogger));
}
}
return taskListener;
}

private PluginLogger createLogger(final TaskListener listener) {
return new PluginLogger(listener.getLogger(), "GitHub Checks");
consoleLogger.logEachLine(causeLogger.getErrorMessages());
return Optional.empty();
}
}
Loading

0 comments on commit a0c5db0

Please sign in to comment.