package org.jenkinsci.plugins.jvctg.perform; import static com.google.common.base.Charsets.UTF_8; import static com.google.common.base.Strings.isNullOrEmpty; import static com.google.common.base.Throwables.propagate; import static com.google.common.collect.Lists.newArrayList; import static java.util.logging.Level.SEVERE; import static org.jenkinsci.plugins.jvctg.config.CredentialsHelper.findCredentials; import static org.jenkinsci.plugins.jvctg.config.ViolationsToGitHubConfigHelper.FIELD_COMMENTONLYCHANGEDCONTENT; import static org.jenkinsci.plugins.jvctg.config.ViolationsToGitHubConfigHelper.FIELD_CREATECOMMENTWITHALLSINGLEFILECOMMENTS; import static org.jenkinsci.plugins.jvctg.config.ViolationsToGitHubConfigHelper.FIELD_CREATESINGLEFILECOMMENTS; import static org.jenkinsci.plugins.jvctg.config.ViolationsToGitHubConfigHelper.FIELD_CREDENTIALSID; import static org.jenkinsci.plugins.jvctg.config.ViolationsToGitHubConfigHelper.FIELD_GITHUBURL; import static org.jenkinsci.plugins.jvctg.config.ViolationsToGitHubConfigHelper.FIELD_KEEP_OLD_COMMENTS; import static org.jenkinsci.plugins.jvctg.config.ViolationsToGitHubConfigHelper.FIELD_MINSEVERITY; import static org.jenkinsci.plugins.jvctg.config.ViolationsToGitHubConfigHelper.FIELD_OAUTH2TOKEN; import static org.jenkinsci.plugins.jvctg.config.ViolationsToGitHubConfigHelper.FIELD_PULLREQUESTID; import static org.jenkinsci.plugins.jvctg.config.ViolationsToGitHubConfigHelper.FIELD_REPOSITORYNAME; import static org.jenkinsci.plugins.jvctg.config.ViolationsToGitHubConfigHelper.FIELD_REPOSITORYOWNER; import static se.bjurr.violations.comments.github.lib.ViolationCommentsToGitHubApi.violationCommentsToGitHubApi; import static se.bjurr.violations.lib.ViolationsApi.violationsApi; import static se.bjurr.violations.lib.parsers.FindbugsParser.setFindbugsMessagesXml; import com.cloudbees.plugins.credentials.common.StandardCredentials; import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; import com.google.common.io.CharStreams; import hudson.EnvVars; import hudson.FilePath; import hudson.FilePath.FileCallable; import hudson.model.Run; import hudson.model.TaskListener; import hudson.remoting.VirtualChannel; import hudson.util.Secret; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; import java.net.MalformedURLException; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.jenkinsci.plugins.jvctg.config.ViolationConfig; import org.jenkinsci.plugins.jvctg.config.ViolationsToGitHubConfig; import org.jenkinsci.plugins.plaincredentials.StringCredentials; import org.jenkinsci.remoting.RoleChecker; import se.bjurr.violations.comments.github.lib.ViolationCommentsToGitHubApi; import se.bjurr.violations.comments.lib.ViolationsLogger; import se.bjurr.violations.lib.model.SEVERITY; import se.bjurr.violations.lib.model.Violation; import se.bjurr.violations.lib.reports.Parser; import se.bjurr.violations.lib.util.Filtering; public class JvctgPerformer { private static Logger LOG = Logger.getLogger(JvctgPerformer.class.getSimpleName()); @VisibleForTesting public static void doPerform( final ViolationsToGitHubConfig config, final File workspace, final StandardCredentials credentials, final TaskListener listener) throws MalformedURLException { if (isNullOrEmpty(config.getPullRequestId())) { listener .getLogger() .println("No pull request id defined, will not send violation comments to GitHub."); return; } final Integer pullRequestIdInt = Integer.valueOf(config.getPullRequestId()); final List<Violation> allParsedViolations = newArrayList(); for (final ViolationConfig violationConfig : config.getViolationConfigs()) { if (!isNullOrEmpty(violationConfig.getPattern())) { List<Violation> parsedViolations = violationsApi() // .findAll(violationConfig.getParser()) // .withReporter(violationConfig.getReporter()) // .inFolder(workspace.getAbsolutePath()) // .withPattern(violationConfig.getPattern()) // .violations(); final SEVERITY minSeverity = config.getMinSeverity(); if (minSeverity != null) { parsedViolations = Filtering.withAtLEastSeverity(parsedViolations, minSeverity); } allParsedViolations.addAll(parsedViolations); listener .getLogger() .println( "Found " + parsedViolations.size() + " violations from " + violationConfig + "."); } } listener .getLogger() .println( "PR: " + config.getRepositoryOwner() + "/" + config.getRepositoryName() + "/" + config.getPullRequestId() + (isNullOrEmpty(config.getGitHubUrl()) ? "" : " on " + config.getGitHubUrl())); try { final ViolationCommentsToGitHubApi g = violationCommentsToGitHubApi(); if (!isNullOrEmpty(config.getoAuth2Token())) { g // .withoAuth2Token(config.getoAuth2Token()); } else if (credentials instanceof StringCredentials) { final StringCredentials token = (StringCredentials) credentials; g // .withoAuth2Token(Secret.toString(token.getSecret())); } else if (credentials instanceof StandardUsernamePasswordCredentials) { final StandardUsernamePasswordCredentials usernamePassword = (StandardUsernamePasswordCredentials) credentials; g // .withUsername(usernamePassword.getUsername()) // .withPassword(Secret.toString(usernamePassword.getPassword())); } final String commentTemplate = config.getCommentTemplate(); g // .withGitHubUrl(config.getGitHubUrl()) // .withPullRequestId(pullRequestIdInt) // .withRepositoryName(config.getRepositoryName()) // .withRepositoryOwner(config.getRepositoryOwner()) // .withViolations(allParsedViolations) // .withCreateCommentWithAllSingleFileComments( config.getCreateCommentWithAllSingleFileComments()) // .withCreateSingleFileComments(config.getCreateSingleFileComments()) // .withCommentOnlyChangedContent(config.getCommentOnlyChangedContent()) // .withCommentOnlyChangedFiles(config.getCommentOnlyChangedFiles()) // .withKeepOldComments(config.isKeepOldComments()) // .withCommentTemplate(commentTemplate) // .withMaxNumberOfViolations(config.getMaxNumberOfViolations()) // .withViolationsLogger( new ViolationsLogger() { @Override public void log(final Level level, final String string) { listener.getLogger().println(level + " " + string); } @Override public void log(final Level level, final String string, final Throwable t) { final StringWriter sw = new StringWriter(); t.printStackTrace(new PrintWriter(sw)); listener.getLogger().println(level + " " + string + "\n" + sw.toString()); } }) // .toPullRequest(); } catch (final Exception e) { Logger.getLogger(JvctgPerformer.class.getName()).log(SEVERE, "", e); final StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); listener.getLogger().println(sw.toString()); } } /** Makes sure any Jenkins variable, used in the configuration fields, are evaluated. */ @VisibleForTesting static ViolationsToGitHubConfig expand( final ViolationsToGitHubConfig config, final EnvVars environment) { final ViolationsToGitHubConfig expanded = new ViolationsToGitHubConfig(); expanded.setGitHubUrl(environment.expand(config.getGitHubUrl())); expanded.setPullRequestId(environment.expand(config.getPullRequestId())); expanded.setRepositoryName(environment.expand(config.getRepositoryName())); expanded.setRepositoryOwner(environment.expand(config.getRepositoryOwner())); expanded.setCreateCommentWithAllSingleFileComments( config.getCreateCommentWithAllSingleFileComments()); expanded.setCreateSingleFileComments(config.getCreateSingleFileComments()); expanded.setCommentOnlyChangedContent(config.getCommentOnlyChangedContent()); expanded.setCommentOnlyChangedFiles(config.getCommentOnlyChangedFiles()); expanded.setMinSeverity(config.getMinSeverity()); expanded.setCredentialsId(config.getCredentialsId()); expanded.setoAuth2Token(environment.expand(config.getoAuth2Token())); expanded.setKeepOldComments(config.isKeepOldComments()); expanded.setCommentTemplate(config.getCommentTemplate()); expanded.setMaxNumberOfViolations(config.getMaxNumberOfViolations()); for (final ViolationConfig violationConfig : config.getViolationConfigs()) { final String pattern = environment.expand(violationConfig.getPattern()); final String reporter = violationConfig.getReporter(); final Parser parser = violationConfig.getParser(); if (isNullOrEmpty(pattern) || parser == null) { LOG.fine("Ignoring violationConfig because of null/empty -values: " + violationConfig); continue; } final ViolationConfig p = new ViolationConfig(); p.setPattern(pattern); p.setReporter(reporter); p.setParser(parser); expanded.getViolationConfigs().add(p); } return expanded; } public static void jvctsPerform( final ViolationsToGitHubConfig configUnexpanded, final FilePath fp, final Run<?, ?> build, final TaskListener listener) { final PrintStream logger = listener.getLogger(); try { final EnvVars env = build.getEnvironment(listener); final ViolationsToGitHubConfig configExpanded = expand(configUnexpanded, env); logger.println("---"); logger.println("--- Jenkins Violation Comments to GitHub ---"); logger.println("---"); logConfiguration(configExpanded, build, listener); final Optional<StandardCredentials> credentials = findCredentials( build.getParent(), configExpanded.getCredentialsId(), configExpanded.getGitHubUrl()); if (!isNullOrEmpty(configExpanded.getoAuth2Token())) { logger.println("Using OAuth2Token"); } else if (credentials.isPresent()) { final StandardCredentials standardCredentials = credentials.get(); if (standardCredentials instanceof StandardUsernamePasswordCredentials) { logger.println("Using username / password"); } else if (standardCredentials instanceof StringCredentials) { logger.println("Using OAuth2Token credential style"); } } else { throw new IllegalStateException("No credentials found!"); } logger.println("Running Jenkins Violation Comments To GitHub"); logger.println("PR " + configExpanded.getPullRequestId()); fp.act( new FileCallable<Void>() { private static final long serialVersionUID = 6166111757469534436L; @Override public void checkRoles(final RoleChecker checker) throws SecurityException {} @Override public Void invoke(final File workspace, final VirtualChannel channel) throws IOException, InterruptedException { setupFindBugsMessages(); listener.getLogger().println("Workspace: " + workspace.getAbsolutePath()); doPerform(configExpanded, workspace, credentials.orNull(), listener); return null; } }); } catch (final Exception e) { Logger.getLogger(JvctgPerformer.class.getName()).log(SEVERE, "", e); final StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); logger.println(sw.toString()); return; } } private static void logConfiguration( final ViolationsToGitHubConfig config, final Run<?, ?> build, final TaskListener listener) { final PrintStream logger = listener.getLogger(); logger.println(FIELD_GITHUBURL + ": " + config.getGitHubUrl()); logger.println(FIELD_REPOSITORYOWNER + ": " + config.getRepositoryOwner()); logger.println(FIELD_REPOSITORYNAME + ": " + config.getRepositoryName()); logger.println(FIELD_PULLREQUESTID + ": " + config.getPullRequestId()); logger.println(FIELD_CREDENTIALSID + ": " + !isNullOrEmpty(config.getCredentialsId())); logger.println(FIELD_OAUTH2TOKEN + ": " + !isNullOrEmpty(config.getoAuth2Token())); logger.println(FIELD_CREATESINGLEFILECOMMENTS + ": " + config.getCreateSingleFileComments()); logger.println( FIELD_CREATECOMMENTWITHALLSINGLEFILECOMMENTS + ": " + config.getCreateCommentWithAllSingleFileComments()); logger.println(FIELD_COMMENTONLYCHANGEDCONTENT + ": " + config.getCommentOnlyChangedContent()); logger.println("commentOnlyChangedFiles: " + config.getCommentOnlyChangedFiles()); logger.println(FIELD_MINSEVERITY + ": " + config.getMinSeverity()); logger.println(FIELD_KEEP_OLD_COMMENTS + ": " + config.isKeepOldComments()); logger.println("commentTemplate: " + config.getCommentTemplate()); logger.println("maxNumberOfViolations: " + config.getMaxNumberOfViolations()); for (final ViolationConfig violationConfig : config.getViolationConfigs()) { logger.println( violationConfig.getReporter() + " with pattern " + violationConfig.getPattern()); } } private static void setupFindBugsMessages() { try { final String findbugsMessagesXml = CharStreams.toString( new InputStreamReader( JvctgPerformer.class.getResourceAsStream("findbugs-messages.xml"), UTF_8)); setFindbugsMessagesXml(findbugsMessagesXml); } catch (final IOException e) { propagate(e); } } }