Fix #583 : Commit status fail on push events

This commit is contained in:
Stephane Brassely 2017-07-10 18:09:13 +02:00
parent 7063999fee
commit 8d7a8c807e
2 changed files with 198 additions and 52 deletions

View File

@ -26,6 +26,7 @@ import com.dabsquared.gitlabjenkins.gitlab.api.model.BuildState;
import hudson.EnvVars;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.plugins.git.Revision;
import hudson.plugins.git.util.Build;
import hudson.plugins.git.util.BuildData;
import jenkins.model.Jenkins;
@ -100,64 +101,93 @@ public class CommitStatusUpdater {
return Jenkins.getInstance().getRootUrl() + build.getUrl();
}
private static List<GitLabBranchBuild> retrieveGitlabProjectIds(Run<?, ?> build, EnvVars environment) {
LOGGER.log(Level.INFO, "Retrieving gitlab project ids");
final List<GitLabBranchBuild> result = new ArrayList<>();
GitLabWebHookCause cause = build.getCause(GitLabWebHookCause.class);
if (cause != null) {
return Collections.singletonList(new GitLabBranchBuild(cause.getData().getSourceProjectId().toString(), cause.getData().getLastCommit()));
}
private static List<GitLabBranchBuild> retrieveGitlabProjectIds(Run<?, ?> build, EnvVars environment) {
LOGGER.log(Level.INFO, "Retrieving gitlab project ids");
final List<GitLabBranchBuild> result = new ArrayList<>();
final GitLabApi gitLabClient = getClient(build);
if (gitLabClient == null) {
LOGGER.log(Level.WARNING, "No gitlab client found.");
return result;
}
GitLabWebHookCause cause = build.getCause(GitLabWebHookCause.class);
if (cause != null) {
return Collections.singletonList(new GitLabBranchBuild(cause.getData().getSourceProjectId().toString(),
cause.getData().getLastCommit()));
}
final SCMRevisionAction scmRevisionAction = build.getAction(SCMRevisionAction.class);
final GitLabApi gitLabClient = getClient(build);
if (gitLabClient == null) {
LOGGER.log(Level.WARNING, "No gitlab client found.");
return result;
}
final SCMRevision scmRevision = scmRevisionAction.getRevision();
final List<BuildData> buildDatas = build.getActions(BuildData.class);
if (CollectionUtils.isEmpty(buildDatas)) {
LOGGER.log(Level.INFO, "Build does not contain build data.");
return result;
}
String scmRevisionHash = null;
if (scmRevision instanceof AbstractGitSCMSource.SCMRevisionImpl) {
scmRevisionHash = ((AbstractGitSCMSource.SCMRevisionImpl) scmRevision).getHash();
}
final List<BuildData> buildDatas = build.getActions(BuildData.class);
if(CollectionUtils.isEmpty(buildDatas)) {
LOGGER.log(Level.INFO, "Build does not contain build data.");
return result;
}
if (buildDatas.size() == 1) {
addGitLabBranchBuild(result, getBuildRevision(build), buildDatas.get(0).getRemoteUrls(), environment, gitLabClient);
} else {
final SCMRevisionAction scmRevisionAction = build.getAction(SCMRevisionAction.class);
for(final BuildData buildData : buildDatas) {
for(final Entry<String, Build> buildByBranchName : buildData.getBuildsByBranchName().entrySet()) {
if(buildByBranchName.getValue().getSHA1().equals(ObjectId.fromString(scmRevisionHash))) {
final Set<String> remoteUrls = buildData.getRemoteUrls();
for (String remoteUrl : remoteUrls) {
try {
LOGGER.log(Level.INFO, "Retrieving the gitlab project id from remote url {0}", remoteUrl);
final String projectNameWithNameSpace = ProjectIdUtil.retrieveProjectId(environment.expand(remoteUrl));
if (StringUtils.isNotBlank(projectNameWithNameSpace)) {
String projectId = projectNameWithNameSpace;
if (projectNameWithNameSpace.contains(".")) {
try {
projectId = gitLabClient.getProject(projectNameWithNameSpace).getId().toString();
} catch (WebApplicationException | ProcessingException e) {
LOGGER.log(Level.SEVERE, String.format("Failed to retrieve projectId for project '%s'", projectNameWithNameSpace), e);
}
}
result.add(new GitLabBranchBuild(projectId, scmRevisionHash));
}
} catch (ProjectIdUtil.ProjectIdResolutionException e) {
}
}
}
}
}
final SCMRevision scmRevision = scmRevisionAction.getRevision();
return result;
}
String scmRevisionHash = null;
if (scmRevision instanceof AbstractGitSCMSource.SCMRevisionImpl) {
scmRevisionHash = ((AbstractGitSCMSource.SCMRevisionImpl) scmRevision).getHash();
}
for (final BuildData buildData : buildDatas) {
for (final Entry<String, Build> buildByBranchName : buildData.getBuildsByBranchName().entrySet()) {
if (buildByBranchName.getValue().getSHA1().equals(ObjectId.fromString(scmRevisionHash))) {
addGitLabBranchBuild(result, scmRevisionHash, buildData.getRemoteUrls(), environment, gitLabClient);
}
}
}
}
return result;
}
private static String getBuildRevision(Run<?, ?> build) {
GitLabWebHookCause cause = build.getCause(GitLabWebHookCause.class);
if (cause != null) {
return cause.getData().getLastCommit();
}
BuildData action = build.getAction(BuildData.class);
if (action == null) {
throw new IllegalStateException("No (git-plugin) BuildData associated to current build");
}
Revision lastBuiltRevision = action.getLastBuiltRevision();
if (lastBuiltRevision == null) {
throw new IllegalStateException("Last build has no associated commit");
}
return action.getLastBuild(lastBuiltRevision.getSha1()).getMarked().getSha1String();
}
private static void addGitLabBranchBuild(List<GitLabBranchBuild> result, String scmRevisionHash,
Set<String> remoteUrls, EnvVars environment, GitLabApi gitLabClient) {
for (String remoteUrl : remoteUrls) {
try {
LOGGER.log(Level.INFO, "Retrieving the gitlab project id from remote url {0}", remoteUrl);
final String projectNameWithNameSpace = ProjectIdUtil.retrieveProjectId(environment.expand(remoteUrl));
if (StringUtils.isNotBlank(projectNameWithNameSpace)) {
String projectId = projectNameWithNameSpace;
if (projectNameWithNameSpace.contains(".")) {
try {
projectId = gitLabClient.getProject(projectNameWithNameSpace).getId().toString();
} catch (WebApplicationException | ProcessingException e) {
LOGGER.log(Level.SEVERE, String.format("Failed to retrieve projectId for project '%s'",
projectNameWithNameSpace), e);
}
}
result.add(new GitLabBranchBuild(projectId, scmRevisionHash));
}
} catch (ProjectIdUtil.ProjectIdResolutionException e) {
}
}
}
public static class GitLabBranchBuild {
private final String projectId;

View File

@ -143,6 +143,20 @@ public class GitLabCommitStatusPublisherTest {
mockServerClient.verify(requests);
}
@Test
public void runningWithLibrary() throws UnsupportedEncodingException {
HttpRequest[] requests = new HttpRequest[] {
prepareExistsCommitWithSuccessResponse("test/project", SHA1),
prepareUpdateCommitStatusWithSuccessResponse("test/project", SHA1, jenkins.getInstance().getRootUrl() + "/build/123", BuildState.running)
};
AbstractBuild build = mockBuildWithLibrary(SHA1, "/build/123", GIT_LAB_CONNECTION, null, "test/project.git");
GitLabCommitStatusPublisher publisher = new GitLabCommitStatusPublisher("jenkins", false);
publisher.prebuild(build, listener);
mockServerClient.verify(requests);
}
@Test
public void runningWithDotInProjectId() throws IOException {
HttpRequest[] requests = new HttpRequest[] {
@ -172,6 +186,20 @@ public class GitLabCommitStatusPublisherTest {
mockServerClient.verify(requests);
}
@Test
public void canceledWithLibrary() throws IOException, InterruptedException {
HttpRequest[] requests = new HttpRequest[] {
prepareExistsCommitWithSuccessResponse("test/project", SHA1),
prepareUpdateCommitStatusWithSuccessResponse("test/project", SHA1, jenkins.getInstance().getRootUrl() + "/build/123", BuildState.canceled)
};
AbstractBuild build = mockBuildWithLibrary(SHA1, "/build/123", GIT_LAB_CONNECTION, Result.ABORTED, "test/project.git");
GitLabCommitStatusPublisher publisher = new GitLabCommitStatusPublisher("jenkins", false);
publisher.perform(build, null, listener);
mockServerClient.verify(requests);
}
@Test
public void success() throws IOException, InterruptedException {
HttpRequest[] requests = new HttpRequest[] {
@ -186,6 +214,20 @@ public class GitLabCommitStatusPublisherTest {
mockServerClient.verify(requests);
}
@Test
public void successWithLibrary() throws IOException, InterruptedException {
HttpRequest[] requests = new HttpRequest[] {
prepareExistsCommitWithSuccessResponse("test/project", SHA1),
prepareUpdateCommitStatusWithSuccessResponse("test/project", SHA1, jenkins.getInstance().getRootUrl() + "/build/123", BuildState.success)
};
AbstractBuild build = mockBuildWithLibrary(SHA1, "/build/123", GIT_LAB_CONNECTION, Result.SUCCESS, "test/project.git");
GitLabCommitStatusPublisher publisher = new GitLabCommitStatusPublisher("jenkins", false);
publisher.perform(build, null, listener);
mockServerClient.verify(requests);
}
@Test
public void failed() throws IOException, InterruptedException {
HttpRequest[] requests = new HttpRequest[] {
@ -200,6 +242,20 @@ public class GitLabCommitStatusPublisherTest {
mockServerClient.verify(requests);
}
@Test
public void failedWithLibrary() throws IOException, InterruptedException {
HttpRequest[] requests = new HttpRequest[] {
prepareExistsCommitWithSuccessResponse("test/project", SHA1),
prepareUpdateCommitStatusWithSuccessResponse("test/project", SHA1, jenkins.getInstance().getRootUrl() + "/build/123", BuildState.failed)
};
AbstractBuild build = mockBuildWithLibrary(SHA1, "/build/123", GIT_LAB_CONNECTION, Result.FAILURE, "test/project.git");
GitLabCommitStatusPublisher publisher = new GitLabCommitStatusPublisher("jenkins", false);
publisher.perform(build, null, listener);
mockServerClient.verify(requests);
}
@Test
public void unstable() throws IOException, InterruptedException {
HttpRequest[] requests = new HttpRequest[] {
@ -214,6 +270,20 @@ public class GitLabCommitStatusPublisherTest {
mockServerClient.verify(requests);
}
@Test
public void unstableWithLibrary() throws IOException, InterruptedException {
HttpRequest[] requests = new HttpRequest[] {
prepareExistsCommitWithSuccessResponse("test/project", SHA1),
prepareUpdateCommitStatusWithSuccessResponse("test/project", SHA1, jenkins.getInstance().getRootUrl() + "/build/123", BuildState.failed)
};
AbstractBuild build = mockBuildWithLibrary(SHA1, "/build/123", GIT_LAB_CONNECTION, Result.UNSTABLE, "test/project.git");
GitLabCommitStatusPublisher publisher = new GitLabCommitStatusPublisher("jenkins", false);
publisher.perform(build, null, listener);
mockServerClient.verify(requests);
}
@Test
public void unstableAsSuccess() throws IOException, InterruptedException {
HttpRequest[] requests = new HttpRequest[] {
@ -315,6 +385,40 @@ public class GitLabCommitStatusPublisherTest {
}
private AbstractBuild mockBuild(String sha, String buildUrl, String gitLabConnection, Result result, String... remoteUrls) {
AbstractBuild build = mock(AbstractBuild.class);
List<BuildData> buildDatas = new ArrayList<BuildData>();
BuildData buildData = mock(BuildData.class);
Revision revision = mock(Revision.class);
when(revision.getSha1String()).thenReturn(sha);
when(buildData.getLastBuiltRevision()).thenReturn(revision);
when(buildData.getRemoteUrls()).thenReturn(new HashSet<>(Arrays.asList(remoteUrls)));
Build gitBuild = mock(Build.class);
when(gitBuild.getMarked()).thenReturn(revision);
when(buildData.getLastBuild(any(ObjectId.class))).thenReturn(gitBuild);
buildDatas.add(buildData);
when(build.getActions(BuildData.class)).thenReturn(buildDatas);
when(build.getAction(BuildData.class)).thenReturn(buildData);
when(build.getResult()).thenReturn(result);
when(build.getUrl()).thenReturn(buildUrl);
AbstractProject<?, ?> project = mock(AbstractProject.class);
when(project.getProperty(GitLabConnectionProperty.class)).thenReturn(new GitLabConnectionProperty(gitLabConnection));
when(build.getProject()).thenReturn(project);
EnvVars environment = mock(EnvVars.class);
when(environment.expand(anyString())).thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
return (String) invocation.getArguments()[0];
}
});
try {
when(build.getEnvironment(any(TaskListener.class))).thenReturn(environment);
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
return build;
}
private AbstractBuild mockBuildWithLibrary(String sha, String buildUrl, String gitLabConnection, Result result, String... remoteUrls) {
AbstractBuild build = mock(AbstractBuild.class);
List<BuildData> buildDatas = new ArrayList<BuildData>();
BuildData buildData = mock(BuildData.class);
@ -339,6 +443,17 @@ public class GitLabCommitStatusPublisherTest {
buildsByBranchName.put("develop", gitBuild);
when(buildData.getBuildsByBranchName()).thenReturn(buildsByBranchName);
buildDatas.add(buildData);
//Second build data (@librabry)
BuildData buildDataLib = mock(BuildData.class);
Revision revisionLib = mock(Revision.class);
when(revisionLib.getSha1String()).thenReturn("SHALIB");
when(buildDataLib.getLastBuiltRevision()).thenReturn(revisionLib);
Build gitBuildLib = mock(Build.class);
when(gitBuildLib.getMarked()).thenReturn(revisionLib);
when(buildDataLib.getLastBuild(any(ObjectId.class))).thenReturn(gitBuildLib);
buildDatas.add(buildDataLib);
when(build.getActions(BuildData.class)).thenReturn(buildDatas);
when(build.getResult()).thenReturn(result);
when(build.getUrl()).thenReturn(buildUrl);
@ -360,6 +475,7 @@ public class GitLabCommitStatusPublisherTest {
}
return build;
}
private String getSingleProjectJson(String name,String projectNameWithNamespace, int porjectId) throws IOException {
String nameSpace = projectNameWithNamespace.split("/")[0];
String projectName = projectNameWithNamespace.split("/")[1];