Skip to content
This repository was archived by the owner on Jan 7, 2021. It is now read-only.
Closed
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
@@ -1,14 +1,21 @@
package org.sonar.plugins.stash;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.PostJob;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.issue.ProjectIssues;
import org.sonar.api.resources.Project;
import org.sonar.api.rule.Severity;
import org.sonar.plugins.stash.client.StashClient;
import org.sonar.plugins.stash.client.StashCredentials;
import org.sonar.plugins.stash.exceptions.GitBranchNotFoundOrNotUniqueException;
import org.sonar.plugins.stash.exceptions.StashConfigurationException;
import org.sonar.plugins.stash.exceptions.StashFailBuildException;
import org.sonar.plugins.stash.issue.SonarQubeIssue;
import org.sonar.plugins.stash.issue.SonarQubeIssuesReport;
import org.sonar.plugins.stash.issue.StashDiffReport;
import org.sonar.plugins.stash.issue.StashUser;
Expand All @@ -32,12 +39,14 @@ public StashIssueReportingPostJob(StashPluginConfiguration stashPluginConfigurat

@Override
public void executeOn(Project project, SensorContext context) {

if (!config.hasToNotifyStash()) {
return;
}


SonarQubeIssuesReport issueReport = stashRequestFacade.extractIssueReport(projectIssues, inputFileCache);

try {
SonarQubeIssuesReport issueReport = stashRequestFacade.extractIssueReport(projectIssues, inputFileCache);

int issueThreshold = stashRequestFacade.getIssueThreshold();
String sonarQubeURL = config.getSonarQubeURL();
Expand Down Expand Up @@ -90,8 +99,11 @@ public void executeOn(Project project, SensorContext context) {
issueReport, diffReport, stashClient);
}

stashRequestFacade.postAnalysisOverview(stashProject, repository, stashPullRequestId, sonarQubeURL,
issueThreshold, issueReport, stashClient);
boolean includeAnalysisOverview = config.includeAnalysisOverview();
if (includeAnalysisOverview) {
stashRequestFacade.postAnalysisOverview(stashProject, repository, stashPullRequestId, sonarQubeURL,
issueThreshold, issueReport, stashClient);
}

// if no new issues, plugin approves the pull-request
if (canApprovePullrequest && issueReport.countIssues() == 0) {
Expand All @@ -102,15 +114,64 @@ public void executeOn(Project project, SensorContext context) {
stashRequestFacade.resetPullRequestApproval(stashProject, repository, stashPullRequestId,
stashCredentials.getLogin(), stashClient);
}

}


} catch (GitBranchNotFoundOrNotUniqueException e) {
LOGGER.info("No unique PR: "+ e.getMessage());
} catch (StashConfigurationException e) {
LOGGER.error("Unable to push SonarQube report to Stash: {}", e.getMessage());
LOGGER.debug("Exception stack trace", e);

} catch (StashMissingElementException e) {
LOGGER.error("Process stopped: {}", e.getMessage());
LOGGER.debug("Exception stack trace", e);
} catch (Exception e) {
LOGGER.error("Something unexpected went wrong: {}", e.getMessage(), e);
}

failBuildIfNecessary(project, issueReport);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Main part for #91 - needs to be outside of try... catch since the fail build should even work, if there is no pull request (yet)


}

private void failBuildIfNecessary(Project project, SonarQubeIssuesReport issueReport) {
// also, if there are issues plugin can fail the build
String failForIssuesWithSeverity = config.failForIssuesWithSeverity();
LOGGER.debug("issueReport={}",issueReport);

if (issueReport!=null
&& issueReport.countIssues() > 0
&& StringUtils.isNotBlank(failForIssuesWithSeverity)
&& !StringUtils.equals(failForIssuesWithSeverity, StashPlugin.SEVERITY_NONE)) {
List<SonarQubeIssue> issues = issueReport.getIssues();

int failForIssueSeverityAsInt = Severity.ALL.indexOf(failForIssuesWithSeverity.trim().toUpperCase());

if (failForIssueSeverityAsInt > -1) {
int issueCountToFailFor = 0;

for (SonarQubeIssue issue : issues) {
int issueSeverityAsInt = Severity.ALL.indexOf(String.valueOf(issue.getSeverity()).trim().toUpperCase());
if (issueSeverityAsInt >= failForIssueSeverityAsInt) {
LOGGER.debug("Breaking build because of issue {} that has a severity equal or higher than '{}'",
issue, failForIssuesWithSeverity);
issueCountToFailFor++;
}
}

if (issueCountToFailFor > 0) {
String msg = "Project " + project.getName() + " has " + issueCountToFailFor
+ " issues that are of severity equal or higher than " + failForIssuesWithSeverity;
LOGGER.error(msg);
throw new StashFailBuildException(msg);
}
} else {
LOGGER.warn("Invalid configuration for {}: '{}' is not a valid Sonar severity, skipping fail-build-check.",
StashPlugin.STASH_FAIL_FOR_ISSUES_WITH_SEVERITY, failForIssuesWithSeverity);
}

}
}

/*
Expand Down
33 changes: 30 additions & 3 deletions src/main/java/org/sonar/plugins/stash/StashPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public class StashPlugin extends SonarPlugin {
private static final String DEFAULT_STASH_TIMEOUT_VALUE = "10000";
private static final String DEFAULT_STASH_THRESHOLD_VALUE = "100";

private static final boolean DEFAULT_STASH_ANALYSIS_OVERVIEW = false;

private static final String CONFIG_PAGE_SUB_CATEGORY_STASH = "Stash";

public static final String SEVERITY_NONE = "NONE";
Expand All @@ -38,11 +40,14 @@ public class StashPlugin extends SonarPlugin {
public static final String STASH_PROJECT = "sonar.stash.project";
public static final String STASH_REPOSITORY = "sonar.stash.repository";
public static final String STASH_PULL_REQUEST_ID = "sonar.stash.pullrequest.id";
public static final String STASH_PULL_REQUEST_BRANCH = "sonar.stash.pullrequest.branch";
public static final String STASH_INCLUDE_ANALYSIS_OVERVIEW = "sonar.stash.include.analysis.overview";
public static final String STASH_RESET_COMMENTS = "sonar.stash.comments.reset";
public static final String STASH_URL = "sonar.stash.url";
public static final String STASH_LOGIN = "sonar.stash.login";
public static final String STASH_PASSWORD = "sonar.stash.password";
public static final String STASH_REVIEWER_APPROVAL = "sonar.stash.reviewer.approval";
public static final String STASH_FAIL_FOR_ISSUES_WITH_SEVERITY = "sonar.stash.failForIssuesWithSeverity";
public static final String STASH_ISSUE_THRESHOLD = "sonar.stash.issue.threshold";
public static final String STASH_TIMEOUT = "sonar.stash.timeout";
public static final String SONARQUBE_URL = "sonar.host.url";
Expand All @@ -63,11 +68,17 @@ public List getExtensions() {
.subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)
.onQualifiers(Qualifiers.PROJECT).build(),
PropertyDefinition.builder(STASH_LOGIN)
.name("Stash base User")
.name("Stash base user")
.description("User to push data on Stash instance")
.subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)
.onQualifiers(Qualifiers.PROJECT).build(),
PropertyDefinition.builder(STASH_TIMEOUT)
PropertyDefinition.builder(STASH_PASSWORD)
.name("Password for base user")
.description("PW for stash user")
.type(PropertyType.PASSWORD)
.subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)
.onQualifiers(Qualifiers.PROJECT).build(),
PropertyDefinition.builder(STASH_TIMEOUT)
.name("Stash issue Timeout")
.description("Timeout when pushing a new issue to Stash (in ms)")
.subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)
Expand All @@ -80,6 +91,14 @@ public List getExtensions() {
.onQualifiers(Qualifiers.PROJECT)
.type(PropertyType.BOOLEAN)
.defaultValue("false").build(),
PropertyDefinition.builder(STASH_FAIL_FOR_ISSUES_WITH_SEVERITY)
.name("Stash Fail Build")
.description("Fails build if issues with equal or higher severity exist")
.subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)
.onQualifiers(Qualifiers.PROJECT)
.type(PropertyType.SINGLE_SELECT_LIST)
.defaultValue(SEVERITY_NONE)
.options(ListUtils.sum(Arrays.asList(SEVERITY_NONE), SEVERITY_LIST)).build(),
PropertyDefinition.builder(STASH_ISSUE_THRESHOLD)
.name("Stash issue Threshold")
.description("Threshold to limit the number of issues pushed to Stash server")
Expand All @@ -93,7 +112,15 @@ public List getExtensions() {
.subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)
.onQualifiers(Qualifiers.PROJECT)
.defaultValue(SEVERITY_NONE)
.options(ListUtils.sum(Arrays.asList(SEVERITY_NONE), SEVERITY_LIST)).build());
.options(ListUtils.sum(Arrays.asList(SEVERITY_NONE), SEVERITY_LIST)).build(),
PropertyDefinition.builder(STASH_INCLUDE_ANALYSIS_OVERVIEW)
.name("Include Analysis Overview Comment")
.description("Set to false to prevent creation of the analysis overview comment.")
.type(PropertyType.BOOLEAN)
.subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)
.onQualifiers(Qualifiers.PROJECT)
.defaultValue(Boolean.toString(DEFAULT_STASH_ANALYSIS_OVERVIEW)).build()
);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public String getPullRequestId() {
return settings.getString(StashPlugin.STASH_PULL_REQUEST_ID);
}

public String getPullRequestBranch() {
return settings.getString(StashPlugin.STASH_PULL_REQUEST_BRANCH);
}

public String getStashURL() {
return settings.getString(StashPlugin.STASH_URL);
}
Expand Down Expand Up @@ -69,4 +73,13 @@ public String getTaskIssueSeverityThreshold() {
public String getSonarQubeVersion() {
return settings.getString(CoreProperties.SERVER_VERSION);
}

public String failForIssuesWithSeverity() {
return settings.getString(StashPlugin.STASH_FAIL_FOR_ISSUES_WITH_SEVERITY);
}

public boolean includeAnalysisOverview() {
return settings.getBoolean(StashPlugin.STASH_INCLUDE_ANALYSIS_OVERVIEW);
}

}
11 changes: 11 additions & 0 deletions src/main/java/org/sonar/plugins/stash/StashRequestFacade.java
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,17 @@ public String getStashRepository() throws StashConfigurationException {
*/
public String getStashPullRequestId() throws StashConfigurationException {
String result = config.getPullRequestId();

if(StringUtils.isNotBlank(config.getPullRequestBranch())) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the main part for #92 - doing this in StashIssueReportingPostJob directly was not that easy (obscure junit test failures) but it would probably cleaner to move it there.

try (StashClient stashClient = new StashClient(getStashURL(), getCredentials(), config.getStashTimeout(), config.getSonarQubeVersion())) {
StashPullRequest pullRequest = stashClient.getPullRequestByBranchName(config.getStashProject(), config.getStashRepository(), config.getPullRequestBranch());
LOGGER.debug("Found PR for branch {}: {}", config.getPullRequestBranch(), pullRequest);
return pullRequest.getId();
} catch (StashClientException e) {
throw new StashConfigurationException(MessageFormat.format(EXCEPTION_STASH_CONF, StashPlugin.STASH_PULL_REQUEST_ID));
}
}

if (result == null){
throw new StashConfigurationException(MessageFormat.format(EXCEPTION_STASH_CONF, StashPlugin.STASH_PULL_REQUEST_ID));
}
Expand Down
28 changes: 27 additions & 1 deletion src/main/java/org/sonar/plugins/stash/client/StashClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.sonar.plugins.stash.StashPlugin;
import org.sonar.plugins.stash.exceptions.StashClientException;
import org.sonar.plugins.stash.exceptions.StashReportExtractionException;
import org.sonar.plugins.stash.exceptions.GitBranchNotFoundOrNotUniqueException;
import org.sonar.plugins.stash.issue.StashComment;
import org.sonar.plugins.stash.issue.StashCommentReport;
import org.sonar.plugins.stash.issue.StashDiffReport;
Expand All @@ -26,6 +27,9 @@
import org.sonar.plugins.stash.issue.StashUser;
import org.sonar.plugins.stash.issue.collector.StashCollector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.text.MessageFormat;
Expand All @@ -37,8 +41,10 @@

import static java.net.HttpURLConnection.HTTP_CREATED;

public class StashClient implements AutoCloseable {

public class StashClient implements AutoCloseable {
private static final Logger LOGGER = LoggerFactory.getLogger(StashClient.class);

private final String baseUrl;
private final StashCredentials credentials;
private final int stashTimeout;
Expand All @@ -61,6 +67,7 @@ public class StashClient implements AutoCloseable {

private static final String PULL_REQUEST_APPROVAL_POST_ERROR_MESSAGE = "Unable to change status of pull-request {0} #{1}.";
private static final String PULL_REQUEST_GET_ERROR_MESSAGE = "Unable to retrieve pull-request {0} #{1}.";
private static final String PULL_REQUEST_GET_FOR_BRANCH_ERROR_MESSAGE = "Unable to retrieve pull-request in repo {0} for branch {1}.";
private static final String PULL_REQUEST_PUT_ERROR_MESSAGE = "Unable to update pull-request {0} #{1}.";
private static final String USER_GET_ERROR_MESSAGE = "Unable to retrieve user {0}.";
private static final String COMMENT_POST_ERROR_MESSAGE = "Unable to post a comment to {0} #{1}.";
Expand Down Expand Up @@ -178,6 +185,25 @@ public StashPullRequest getPullRequest(String project, String repository, String
return StashCollector.extractPullRequest(project, repository, pullRequestId, response);
}

public StashPullRequest getPullRequestByBranchName(String project, String repository, String branchName)
throws StashClientException {
String request = MessageFormat.format(REPO_API + "pull-requests?at=refs/heads/{3}&direction=OUTGOING", baseUrl, project, repository, branchName);

JSONObject response = get(request, MessageFormat.format(PULL_REQUEST_GET_FOR_BRANCH_ERROR_MESSAGE, repository, branchName));

Long size = (Long) response.get("size");
if(size==0) {
throw new GitBranchNotFoundOrNotUniqueException("Found no PR for branch "+branchName + " in repo "+repository);
} else if(size==1) {
Copy link

@jannylund jannylund Dec 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if you run a git-flow branching scheme and make a hotfix commit with PR towards both develop and master (if they happen to be in sync). That case would likely trigger size == 2 and still be valid, right?

// the expected case
JSONObject prJsonObject = (JSONObject) ((JSONArray) response.get("values")).get(0);
Long prId = (Long) prJsonObject.get("id");
return StashCollector.extractPullRequest(project, repository, String.valueOf(prId), prJsonObject);
} else {
throw new GitBranchNotFoundOrNotUniqueException("Found "+size+" PRs for branch "+branchName + " in repo "+repository);
}
}

public void addPullRequestReviewer(String project, String repository, String pullRequestId, long pullRequestVersion, ArrayList<StashUser> reviewers)
throws StashClientException {
String request = MessageFormat.format(API_ONE_PR, baseUrl, project, repository, pullRequestId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.sonar.plugins.stash.exceptions;

public class GitBranchNotFoundOrNotUniqueException extends RuntimeException {

public GitBranchNotFoundOrNotUniqueException(String message) {
super(message);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.sonar.plugins.stash.exceptions;

public class StashFailBuildException extends RuntimeException {

public StashFailBuildException(String message) {
super(message);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public void setUp() throws Exception {
config = mock(StashPluginConfiguration.class);
when(config.hasToNotifyStash()).thenReturn(true);
when(config.canApprovePullRequest()).thenReturn(false);
when(config.includeAnalysisOverview()).thenReturn(true);
when(config.getStashURL()).thenReturn(STASH_URL);
when(config.getSonarQubeURL()).thenReturn(SONARQUBE_URL);
when(config.getStashTimeout()).thenReturn(STASH_TIMEOUT);
Expand Down