diff --git a/README.md b/README.md index 7af13d5..ca5282a 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,8 @@ The plugin will contribute some environment variables to the build. * **gitlabSourceProjectId** * **gitlabTargetProjectId** * **gitlabLastCommitId** +* **gitlabMergeRequestAuthorEmail** +* **gitlabMergeRequestAssigneeEmail** ## Contributing diff --git a/pom.xml b/pom.xml index 7d5d397..5956d5c 100644 --- a/pom.xml +++ b/pom.xml @@ -77,6 +77,11 @@ java-gitlab-api 4.0.0 + + org.jenkins-ci.plugins.workflow + workflow-step-api + 2.14 + diff --git a/src/main/java/org/jenkinsci/plugins/gitlab/GitLabEnvironmentContributor.java b/src/main/java/org/jenkinsci/plugins/gitlab/GitLabEnvironmentContributor.java index 657d16e..2c705d5 100644 --- a/src/main/java/org/jenkinsci/plugins/gitlab/GitLabEnvironmentContributor.java +++ b/src/main/java/org/jenkinsci/plugins/gitlab/GitLabEnvironmentContributor.java @@ -22,6 +22,9 @@ public void buildEnvironmentFor(@Nonnull Run r, @Nonnull EnvVars envs, Map variables = new HashMap<>(); variables.put("gitlabMergeRequestId", cause.getMergeRequestId() + ""); variables.put("gitlabMergeRequestIid", cause.getMergeRequestIid() + ""); + variables.put("gitlabMergeRequestState", cause.getMergeRequestState() + ""); + variables.put("gitlabMergeRequestAuthorEmail", cause.getAuthorEmail()); + variables.put("gitlabMergeRequestAssigneeEmail", cause.getAssigneeEmail()); variables.put("gitlabSourceName", cause.getSourceName()); variables.put("gitlabSourceRepository", cause.getSourceRepository()); variables.put("gitlabSourceBranch", cause.getSourceBranch()); diff --git a/src/main/java/org/jenkinsci/plugins/gitlab/Gitlab.java b/src/main/java/org/jenkinsci/plugins/gitlab/Gitlab.java index 4d9be52..f1e5054 100644 --- a/src/main/java/org/jenkinsci/plugins/gitlab/Gitlab.java +++ b/src/main/java/org/jenkinsci/plugins/gitlab/Gitlab.java @@ -31,7 +31,11 @@ public GitlabAPI get() { } public synchronized GitlabCommitStatus changeCommitStatus(Integer projectId, String branch, String commitHash, String commitStatus, String targetUrl) throws IOException { - GitlabProject project = get().getProject(projectId); - return get().createCommitStatus(project, commitHash, commitStatus, branch, "jenkins", targetUrl, null); + return changeCommitStatus(projectId, branch, commitHash, "Jenkins", "Gitlab MR Builder", commitStatus, targetUrl); + } + + public synchronized GitlabCommitStatus changeCommitStatus(Integer projectId, String branch, String commitHash, String name, String description, String commitStatus, String targetUrl) throws IOException { + GitlabProject project = get().getProject(projectId); + return get().createCommitStatus(project, commitHash, commitStatus, branch, name, targetUrl, description); } } diff --git a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabBuildListener.java b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabBuildListener.java index 8cbce2f..7fd76f7 100644 --- a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabBuildListener.java +++ b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabBuildListener.java @@ -1,33 +1,122 @@ package org.jenkinsci.plugins.gitlab; +import hudson.EnvVars; import hudson.Extension; -import hudson.model.AbstractBuild; +import hudson.model.Result; +import hudson.model.Run; import hudson.model.TaskListener; import hudson.model.listeners.RunListener; +import jenkins.model.Jenkins; +import org.gitlab.api.models.GitlabMergeRequest; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; @Extension -public class GitlabBuildListener extends RunListener { +public class GitlabBuildListener extends RunListener> { - @Override - public void onStarted(AbstractBuild abstractBuild, TaskListener listener) { - GitlabBuildTrigger trigger = GitlabBuildTrigger.getTrigger(abstractBuild.getProject()); + private static final Logger LOGGER = Logger.getLogger(GitlabBuildListener.class.getName()); + + private String getRootUrl() { + Jenkins instance = Jenkins.getInstance(); + return instance == null ? "" : instance.getRootUrl(); + } - if (trigger == null) { + @Override + public void onStarted(Run build, TaskListener listener) { + GitlabCause gitlabCause = build.getCause(GitlabCause.class); + if (gitlabCause == null || gitlabCause.getMergeRequestState().equals(GitlabMergeRequest.STATUS_MERGED)) { return; } + Gitlab gitlab = GitlabBuildTrigger.DESCRIPTOR.getGitlab(); + try { + build.setDescription("" + gitlabCause.getShortDescription() + ""); + String url = getRootUrl() + build.getUrl(); + + LOGGER.log(Level.INFO, "Send running status to commit: " + gitlabCause.getLastCommitId() + ", url:" + url); + gitlab.changeCommitStatus(gitlabCause.getTargetProjectId(), gitlabCause.getSourceBranch(), gitlabCause.getLastCommitId(), "running", url); - trigger.getBuilder().getBuilds().onStarted(abstractBuild); - + if (gitlabCause.getTrigger().getPublishBuildProgressMessages()) { + GitlabMergeRequestWrapper.createNote(gitlabCause.getMergeRequestId(), + gitlabCause.getMergeRequestIid(), + gitlabCause.getSourceProjectId(), "Build Started: " + "[" + url + "](" + url + ")", false, false); + } + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Can't update build description", e); + } } @Override - public void onCompleted(AbstractBuild abstractBuild, TaskListener listener) { - GitlabBuildTrigger trigger = GitlabBuildTrigger.getTrigger(abstractBuild.getProject()); - - if (trigger == null) { + public void onCompleted(Run build, TaskListener listener) { + GitlabCause gitlabCause = build.getCause(GitlabCause.class); + if (gitlabCause == null || gitlabCause.getMergeRequestState().equals(GitlabMergeRequest.STATUS_MERGED)) { return; } + Gitlab gitlab = GitlabBuildTrigger.DESCRIPTOR.getGitlab(); + try { + boolean stable = false; + StringBuilder stringBuilder = new StringBuilder(); + Result result = build.getResult(); + EnvVars envVars = build.getEnvironment(listener); + if (result == Result.SUCCESS) { + stable = true; + if (envVars.containsKey("gitlabSuccessMessage")) { + stringBuilder.append(envVars.get("gitlabSuccessMessage")); + } else { + stringBuilder.append(GitlabBuildTrigger.DESCRIPTOR.getSuccessMessage()); + } + } else if (result == Result.UNSTABLE) { + if (envVars.containsKey("gitlabUnstableMessage")) { + stringBuilder.append(envVars.get("gitlabUnstableMessage")); + } else { + stringBuilder.append(GitlabBuildTrigger.DESCRIPTOR.getUnstableMessage()); + } + } else { + if (envVars.containsKey("gitlabFailureMessage")) { + stringBuilder.append(envVars.get("gitlabFailureMessage")); + } else { + stringBuilder.append(GitlabBuildTrigger.DESCRIPTOR.getFailureMessage()); + } + } + + if (!gitlabCause.getTrigger().getDescriptor().isEnableBuildTriggeredMessage()) { + GitlabBuilds.withCustomParameters(stringBuilder, gitlabCause.getCustomParameters()); + } + + String buildUrl = getRootUrl() + build.getUrl(); + stringBuilder + .append("\nBuild results available at: ") + .append("[") + .append(buildUrl) + .append("](") + .append(buildUrl) + .append(")"); // Link in markdown format + + boolean shouldClose = false; + if (!stable && gitlabCause.getTrigger().getAutoCloseFailed()) { + shouldClose = true; + } - trigger.getBuilder().getBuilds().onCompleted(abstractBuild); + boolean shouldMerge = false; + if (stable && gitlabCause.getTrigger().getAutoMergePassed()) { + shouldMerge = true; + } + + if (gitlabCause.getTrigger().getPublishBuildProgressMessages() || !stable) { + GitlabMergeRequestWrapper.createNote(gitlabCause.getMergeRequestId(), + gitlabCause.getMergeRequestIid(), + gitlabCause.getSourceProjectId(), + stringBuilder.toString(), + shouldClose, + shouldMerge); + } + + String status = (result == Result.SUCCESS) ? "success" : ((result == Result.ABORTED) ? "canceled" : "failed"); + LOGGER.log(Level.INFO, "Send " + status + " status to commit: " + gitlabCause.getLastCommitId() + ", url:" + buildUrl); + gitlab.changeCommitStatus(gitlabCause.getTargetProjectId(), gitlabCause.getSourceBranch(), gitlabCause.getLastCommitId(), status, buildUrl); + } catch (IOException | InterruptedException e) { + LOGGER.log(Level.SEVERE, "Can't update build description", e); + } } } diff --git a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabBuildTrigger.java b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabBuildTrigger.java index 95e5d91..b58e4d4 100755 --- a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabBuildTrigger.java +++ b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabBuildTrigger.java @@ -8,6 +8,8 @@ import hudson.triggers.TriggerDescriptor; import hudson.util.FormValidation; import hudson.util.Secret; +import jenkins.model.Jenkins; +import jenkins.model.ParameterizedJobMixIn; import net.sf.json.JSONObject; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; @@ -20,11 +22,12 @@ import java.util.logging.Level; import java.util.logging.Logger; -public final class GitlabBuildTrigger extends Trigger> { +public final class GitlabBuildTrigger extends Trigger> { private static final Logger LOGGER = Logger.getLogger(GitlabBuildTrigger.class.getName()); private final String projectPath; + private final String sourceBranchRegex; private final String targetBranchRegex; private final boolean useHttpUrl; private final String assigneeFilter; @@ -38,6 +41,7 @@ public final class GitlabBuildTrigger extends Trigger> { @DataBoundConstructor public GitlabBuildTrigger(String cron, String projectPath, + String sourceBranchRegex, String targetBranchRegex, boolean useHttpUrl, String assigneeFilter, @@ -49,6 +53,7 @@ public GitlabBuildTrigger(String cron, super(cron); this.projectPath = projectPath; + this.sourceBranchRegex = sourceBranchRegex; this.targetBranchRegex = targetBranchRegex; this.useHttpUrl = useHttpUrl; this.assigneeFilter = assigneeFilter; @@ -60,7 +65,7 @@ public GitlabBuildTrigger(String cron, } @Override - public void start(AbstractProject project, boolean newInstance) { + public void start(Job project, boolean newInstance) { try { GitlabWebhooks.addTrigger(this); @@ -82,6 +87,9 @@ public QueueTaskFuture startJob(GitlabCause cause) { values.put("gitlabMergeRequestId", new StringParameterValue("gitlabMergeRequestId", String.valueOf(cause.getMergeRequestId()))); values.put("gitlabMergeRequestIid", new StringParameterValue("gitlabMergeRequestIid", String.valueOf(cause.getMergeRequestIid()))); + values.put("gitlabMergeRequestState", new StringParameterValue("gitlabMergeRequestState", String.valueOf(cause.getMergeRequestState()))); + values.put("gitlabMergeRequestAssigneeEmail", new StringParameterValue("gitlabMergeRequestAssigneeEmail", cause.getAssigneeEmail())); + values.put("gitlabMergeRequestAuthorEmail", new StringParameterValue("gitlabMergeRequestAuthorEmail", cause.getAuthorEmail())); values.put("gitlabSourceName", new StringParameterValue("gitlabSourceName", cause.getSourceName())); values.put("gitlabSourceRepository", new StringParameterValue("gitlabSourceRepository", cause.getSourceRepository())); values.put("gitlabSourceBranch", new StringParameterValue("gitlabSourceBranch", cause.getSourceBranch())); @@ -93,11 +101,19 @@ public QueueTaskFuture startJob(GitlabCause cause) { } List listValues = new ArrayList<>(values.values()); - if (job == null) { - return null; - } else { - return job.scheduleBuild2(0, cause, new ParametersAction(listValues)); - } + + ParameterizedJobMixIn scheduledJob = new ParameterizedJobMixIn() { + @Override + protected Job asJob() { + return job; + } + }; + + return scheduledJob.scheduleBuild2( + 0, + new CauseAction(cause), + new ParametersAction(listValues) + ); } private Map getDefaultParameters() { @@ -172,6 +188,10 @@ public String getTargetBranchRegex() { return targetBranchRegex; } + public String getSourceBranchRegex() { + return sourceBranchRegex; + } + public boolean getUseHttpUrl() { return useHttpUrl; } @@ -235,7 +255,7 @@ public GitlabBuildTriggerDescriptor() { @Override public boolean isApplicable(Item item) { - return item instanceof AbstractProject; + return true; } @Override diff --git a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabBuilds.java b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabBuilds.java index 1a0d1b5..a17e362 100755 --- a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabBuilds.java +++ b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabBuilds.java @@ -1,10 +1,6 @@ package org.jenkinsci.plugins.gitlab; -import hudson.model.AbstractBuild; -import hudson.model.Cause; -import hudson.model.Result; import hudson.model.queue.QueueTaskFuture; -import jenkins.model.Jenkins; import java.io.FileNotFoundException; import java.io.IOException; @@ -43,7 +39,15 @@ public String build(GitlabCause cause, Map customParameters, Git String triggerComment = trigger.getTriggerComment(); GitlabNote lastNote = getLastNote(mergeRequest, api); - if (isAllowedByTargetBranchRegex(cause.getTargetBranch())) { + if (isAllowedBySourceBranchRegex(cause.getSourceBranch())) { + LOGGER.log(Level.INFO, "The source regex matches the source branch {" + cause.getSourceBranch() + "}. Target branch {" + cause.getTargetBranch() + "}"); + shouldRun = true; + } else { + LOGGER.log(Level.INFO, "The source regex did not match the source branch {" + cause.getSourceBranch() + "}. Not triggering this job. Target branch {" + cause.getTargetBranch() + "}"); + shouldRun = false; + } + + if (shouldRun && isAllowedByTargetBranchRegex(cause.getTargetBranch())) { LOGGER.log(Level.INFO, "The target regex matches the target branch {" + cause.getTargetBranch() + "}. Source branch {" + cause.getSourceBranch() + "}"); shouldRun = true; } else { @@ -51,12 +55,20 @@ public String build(GitlabCause cause, Map customParameters, Git shouldRun = false; } - if (hasCommitStatus(project, cause.getLastCommitId(), api)) { + LOGGER.log(Level.INFO, "The merge request state: " + mergeRequest.getState() + ", " + cause.getMergeRequestState()); + // state is close + if (mergeRequest.isClosed()) { + LOGGER.log(Level.INFO, "The merge request " + cause.getTitle() + " has been closed."); shouldRun = false; } + if (hasCommitStatus(project, cause.getLastCommitId(), api)) { + LOGGER.log(Level.WARNING, "The merge request " + cause.getTitle() + " has running/pending pipelines."); +// shouldRun = false; + } + if (lastNote != null && lastNote.getBody().equals(triggerComment)) { - LOGGER.info("Trigger comment found"); + LOGGER.log(Level.INFO, "Trigger comment found the merge request " + cause.getTitle()); shouldRun = true; } @@ -90,7 +102,8 @@ public String build(GitlabCause cause, Map customParameters, Git if (build == null) { LOGGER.log(Level.SEVERE, "Job failed to start."); } - return withCustomParameters(new StringBuilder("Build triggered."), customParameters).toString(); + + return GitlabBuilds.withCustomParameters(new StringBuilder("Build triggered."), customParameters).toString(); } else { LOGGER.info("Build is not supposed to run"); return ""; @@ -119,6 +132,16 @@ public boolean isAllowedByTargetBranchRegex(String branchName) { return pattern.matcher(branchName).matches(); } + public boolean isAllowedBySourceBranchRegex(String branchName) { + String regex = trigger.getSourceBranchRegex(); + // Allow when no pattern has been specified. (default behavior) + if (StringUtils.isEmpty(regex)) { + return true; + } + Pattern pattern = Pattern.compile(regex); + return pattern.matcher(branchName).matches(); + } + /** * synchronized so that there can't be a race condition here. * @@ -130,14 +153,19 @@ public boolean isAllowedByTargetBranchRegex(String branchName) { */ private synchronized boolean hasCommitStatus(GitlabProject project, String commitHash, GitlabAPI api) throws IOException { try { + boolean hasPendingOrRunningStatus = false; List statuses = api.getCommitStatuses(project, commitHash); - + // pending, running, for (GitlabCommitStatus status : statuses) { LOGGER.fine("Status of " + commitHash + " -> " + status.getStatus()); + if (status.getStatus().equals("pending") || status.getStatus().equals("running")) { + hasPendingOrRunningStatus = true; + } } // Return true if there are some statuses - return !statuses.isEmpty(); +// return !statuses.isEmpty(); + return hasPendingOrRunningStatus; } catch (FileNotFoundException ex) { // Can ignore this one because it just means that there is no status for a commit @@ -209,7 +237,7 @@ private boolean filterMatch(String filter, String target[], String type) { return shouldRun; } - private StringBuilder withCustomParameters(StringBuilder sb, Map customParameters) { + public static StringBuilder withCustomParameters(StringBuilder sb, Map customParameters) { if (customParameters.isEmpty()) { return sb; } @@ -225,127 +253,4 @@ private StringBuilder withCustomParameters(StringBuilder sb, Map sb.append("\n\n"); return sb; } - - private GitlabCause getCause(AbstractBuild build) { - Cause cause = build.getCause(GitlabCause.class); - - if (cause == null || !(cause instanceof GitlabCause)) { - return null; - } - - return (GitlabCause) cause; - } - - private Result getResult(AbstractBuild build) { - return build.getResult(); - } - - private String getRootUrl() { - Jenkins instance = Jenkins.getInstance(); - return instance == null ? "" : instance.getRootUrl(); - } - - private boolean isEnableBuildTriggeredMessage() { - return trigger.getBuilder().isEnableBuildTriggeredMessage(); - } - - private boolean isPublishBuildProgressMessages() { - return trigger.getPublishBuildProgressMessages(); - } - - /** - * - * @param build AbstractBuild - */ - public void onStarted(AbstractBuild build) { - GitlabCause cause = getCause(build); - - if (cause == null) { - return; - } - - try { - build.setDescription("" + getOnStartedMessage(cause) + ""); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Can't update build description", e); - } - - String url = getRootUrl() + build.getUrl(); - - if (isPublishBuildProgressMessages()) { - repository.createNote(cause.getMergeRequestId(), "Build Started: " + "[" + url + "](" + url + ")", false, false); - } - - repository.changeCommitStatus(cause.getMergeRequestId(), cause.getLastCommitId(), "running", url); - } - - /** - * @param build AbstractBuild - */ - public void onCompleted(AbstractBuild build) { - GitlabCause cause = getCause(build); - - if (cause == null) { - return; - } - - boolean stable = false; - StringBuilder stringBuilder = new StringBuilder(); - Result result = getResult(build); - - if (result == Result.SUCCESS) { - stable = true; - if (build.getBuildVariables().containsKey("gitlabSuccessMessage")) { - stringBuilder.append(build.getBuildVariables().get("gitlabSuccessMessage")); - } else { - stringBuilder.append(trigger.getDescriptor().getSuccessMessage()); - } - } else if (result == Result.UNSTABLE) { - if (build.getBuildVariables().containsKey("gitlabUnstableMessage")) { - stringBuilder.append(build.getBuildVariables().get("gitlabUnstableMessage")); - } else { - stringBuilder.append(trigger.getDescriptor().getUnstableMessage()); - } - } else { - if (build.getBuildVariables().containsKey("gitlabFailureMessage")) { - stringBuilder.append(build.getBuildVariables().get("gitlabFailureMessage")); - } else { - stringBuilder.append(trigger.getDescriptor().getFailureMessage()); - } - } - - if (!isEnableBuildTriggeredMessage()) { - withCustomParameters(stringBuilder, cause.getCustomParameters()); - } - - String buildUrl = getRootUrl() + build.getUrl(); - stringBuilder - .append("\nBuild results available at: ") - .append("[") - .append(buildUrl) - .append("](") - .append(buildUrl) - .append(")"); // Link in markdown format - - boolean shouldClose = false; - if (!stable && trigger.getAutoCloseFailed()) { - shouldClose = true; - } - - boolean shouldMerge = false; - if (stable && trigger.getAutoMergePassed()) { - shouldMerge = true; - } - - if (isPublishBuildProgressMessages() || !stable) { - repository.createNote(cause.getMergeRequestId(), stringBuilder.toString(), shouldClose, shouldMerge); - } - - String status = (result == Result.SUCCESS) ? "success" : "failed"; - repository.changeCommitStatus(cause.getMergeRequestId(), cause.getLastCommitId(), status, buildUrl); - } - - private String getOnStartedMessage(GitlabCause cause) { - return cause.getShortDescription(); - } } diff --git a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabCause.java b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabCause.java index ac5e2fb..4442add 100755 --- a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabCause.java +++ b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabCause.java @@ -7,6 +7,9 @@ public class GitlabCause extends Cause { private final Integer mergeRequestId; private final Integer mergeRequestIid; + private final String mergeRequestState; + private final String assigneeEmail; + private final String authorEmail; private final String sourceName; private final String sourceRepository; private final String sourceBranch; @@ -17,9 +20,15 @@ public class GitlabCause extends Cause { private final Integer sourceProjectId; private final Integer targetProjectId; private final String lastCommitId; + private final String webUrl; + + private GitlabBuildTrigger trigger; public GitlabCause(Integer mergeRequestId, Integer mergeRequestIid, + String mergeRequestState, + String authorEmail, + String assigneeEmail, String sourceName, String sourceRepository, String sourceBranch, @@ -29,10 +38,14 @@ public GitlabCause(Integer mergeRequestId, String description, Integer sourceProjectId, Integer targetProjectId, - String lastCommitId) { + String lastCommitId, + String webUrl) { this.mergeRequestId = mergeRequestId; this.mergeRequestIid = mergeRequestIid; + this.mergeRequestState = mergeRequestState; + this.assigneeEmail = assigneeEmail; + this.authorEmail = authorEmail; this.sourceName = sourceName; this.sourceRepository = sourceRepository; this.sourceBranch = sourceBranch; @@ -43,10 +56,11 @@ public GitlabCause(Integer mergeRequestId, this.sourceProjectId = sourceProjectId; this.targetProjectId = targetProjectId; this.lastCommitId = lastCommitId; + this.webUrl = webUrl; } @Override public String getShortDescription() { - return "Gitlab Merge Request #" + mergeRequestIid + " : " + sourceName + "/" + sourceBranch + + return "Gitlab Merge Request #" + mergeRequestIid + "(" + this.getAuthorEmail() + ")" + " : " + sourceName + "/" + sourceBranch + " => " + targetBranch; } @@ -97,4 +111,28 @@ public Integer getTargetProjectId() { public String getLastCommitId() { return lastCommitId; } + + public String getAssigneeEmail() { + return assigneeEmail; + } + + public String getAuthorEmail() { + return authorEmail; + } + + public String getWebUrl() { + return webUrl; + } + + public GitlabBuildTrigger getTrigger() { + return trigger; + } + + public void setTrigger(GitlabBuildTrigger trigger) { + this.trigger = trigger; + } + + public String getMergeRequestState() { + return mergeRequestState; + } } diff --git a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabMergeRequestAddCommentStep.java b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabMergeRequestAddCommentStep.java new file mode 100644 index 0000000..4a55dac --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabMergeRequestAddCommentStep.java @@ -0,0 +1,102 @@ +package org.jenkinsci.plugins.gitlab; +/* + * + * Edward Chen + * edward_chen@gemdata.net + * 2019-07-22 14:56 + * + * Copyright (c) 2016-2018, GemData. All Right Reserved, http://www.gemdata.net + */ + +import com.google.common.collect.ImmutableSet; +import hudson.Extension; +import hudson.model.Run; +import hudson.model.TaskListener; +import hudson.util.ListBoxModel; +import org.apache.commons.lang.StringUtils; +import org.jenkinsci.plugins.gitlab.models.webhook.BuildState; +import org.jenkinsci.plugins.workflow.steps.*; +import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; +import org.kohsuke.stapler.export.ExportedBean; + +import java.util.EnumSet; +import java.util.Set; +import java.util.logging.Logger; + +@ExportedBean +public class GitlabMergeRequestAddCommentStep extends Step { + + private String comment; + + @DataBoundConstructor + public GitlabMergeRequestAddCommentStep(String comment) { + this.comment = StringUtils.isEmpty(comment) ? null : comment; + } + + @Override + public StepExecution start(StepContext context) throws Exception { + return new AddGitLabCommentStepExecution(context, this); + } + + public String getComment() { + return comment; + } + + @DataBoundSetter + public void setComment(String comment) { + this.comment = StringUtils.isEmpty(comment) ? null : comment; + } + + + public static class AddGitLabCommentStepExecution extends SynchronousStepExecution { + private static final Logger LOGGER = Logger.getLogger(GitlabWebhooks.class.getName()); + + private static final long serialVersionUID = 1; + + private final transient Run run; + + private final transient GitlabMergeRequestAddCommentStep step; + + AddGitLabCommentStepExecution(StepContext context, GitlabMergeRequestAddCommentStep step) throws Exception { + super(context); + this.step = step; + run = context.get(Run.class); + } + + @Override + protected Void run() throws Exception { + final String comment = StringUtils.isEmpty(step.comment) ? "" : step.comment; + GitlabCause gitlabCause = run.getCause(GitlabCause.class); + if (gitlabCause != null) { + LOGGER.info(String.format("Add comment for mr %d:%d:%d", gitlabCause.getMergeRequestId(), gitlabCause.getMergeRequestIid(), gitlabCause.getSourceProjectId())); + GitlabMergeRequestWrapper.createNote(gitlabCause.getMergeRequestId(), + gitlabCause.getMergeRequestIid(), + gitlabCause.getSourceProjectId(), + comment, + false, + false); + } + + return null; + } + } + + @Extension + public static final class DescriptorImpl extends StepDescriptor { + @Override + public String getDisplayName() { + return "[GitlabMRBuilder] Add comment to the merge request in GitLab"; + } + + @Override + public String getFunctionName() { + return "addGitlabMRNote"; + } + + @Override + public Set> getRequiredContext() { + return ImmutableSet.of(TaskListener.class, Run.class); + } + } +} diff --git a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabMergeRequestBuilder.java b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabMergeRequestBuilder.java index 0adb20a..1aa3079 100755 --- a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabMergeRequestBuilder.java +++ b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabMergeRequestBuilder.java @@ -1,12 +1,13 @@ package org.jenkinsci.plugins.gitlab; import hudson.model.AbstractProject; +import hudson.model.Job; import java.util.Map; public class GitlabMergeRequestBuilder { - private AbstractProject project; + private Job project; private GitlabBuildTrigger trigger; private Map mergeRequests; private GitlabBuilds builds; @@ -37,7 +38,7 @@ public GitlabBuildTrigger getTrigger() { return trigger; } - public GitlabMergeRequestBuilder setProject(AbstractProject project) { + public GitlabMergeRequestBuilder setProject(Job project) { this.project = project; return this; } diff --git a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabMergeRequestCommitStatusUpdaterStep.java b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabMergeRequestCommitStatusUpdaterStep.java new file mode 100644 index 0000000..42a1928 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabMergeRequestCommitStatusUpdaterStep.java @@ -0,0 +1,125 @@ +package org.jenkinsci.plugins.gitlab; +/* + * + * Edward Chen + * edward_chen@gemdata.net + * 2019-07-22 14:56 + * + * Copyright (c) 2016-2018, GemData. All Right Reserved, http://www.gemdata.net + */ + +import java.util.EnumSet; +import java.util.Set; + +import org.jenkinsci.plugins.gitlab.models.webhook.BuildState; +import org.jenkinsci.plugins.workflow.steps.*; + +import org.apache.commons.lang.StringUtils; +import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; +import org.kohsuke.stapler.export.ExportedBean; + +import com.google.common.collect.ImmutableSet; + +import hudson.Extension; +import hudson.model.Run; +import hudson.model.TaskListener; +import hudson.util.ListBoxModel; + +@ExportedBean +public class GitlabMergeRequestCommitStatusUpdaterStep extends Step { + + private String name; + private BuildState state; + private String url; + + @DataBoundConstructor + public GitlabMergeRequestCommitStatusUpdaterStep(String name, BuildState state, String url) { + this.name = StringUtils.isEmpty(name) ? null : name; + this.state = state; + this.url = url; + } + + @Override + public StepExecution start(StepContext context) throws Exception { + return new UpdateGitLabCommitStatusStepExecution(context, this); + } + + public String getName() { + return name; + } + + @DataBoundSetter + public void setName(String name) { + this.name = StringUtils.isEmpty(name) ? null : name; + } + + public BuildState getState() { + return state; + } + + @DataBoundSetter + public void setState(BuildState state) { + this.state = state; + } + + public String getUrl() { + return url; + } + + @DataBoundSetter + public void setUrl(String sonarqubeUrl) { + this.url = sonarqubeUrl; + } + + public static class UpdateGitLabCommitStatusStepExecution extends SynchronousStepExecution { + private static final long serialVersionUID = 1; + + private final transient Run run; + + private final transient GitlabMergeRequestCommitStatusUpdaterStep step; + + UpdateGitLabCommitStatusStepExecution(StepContext context, GitlabMergeRequestCommitStatusUpdaterStep step) throws Exception { + super(context); + this.step = step; + run = context.get(Run.class); + } + + @Override + protected Void run() throws Exception { + final String name = StringUtils.isEmpty(step.name) ? "jenkins" : step.name; + Gitlab gitlab = GitlabBuildTrigger.DESCRIPTOR.getGitlab(); + GitlabCause gitlabCause = run.getCause(GitlabCause.class); + if (gitlabCause != null) { + gitlab.changeCommitStatus(gitlabCause.getTargetProjectId(), gitlabCause.getSourceBranch(), gitlabCause.getLastCommitId(), name, "", step.state.toString(), step.url); + } + return null; + } + } + + @Extension + public static final class DescriptorImpl extends StepDescriptor { + @Override + public String getDisplayName() { + return "[GitlabMRBuilder] Update the merge request latest commit status in GitLab"; + } + + @Override + public String getFunctionName() { + return "updateGitlabMRCommitStatus"; + } + + public ListBoxModel doFillStateItems() { + ListBoxModel options = new ListBoxModel(); + for (BuildState buildState : EnumSet.allOf(BuildState.class)) { + options.add(buildState.name()); + } + return options; + } + + @Override + public Set> getRequiredContext() { + return ImmutableSet.of(TaskListener.class, Run.class); + } + } +} diff --git a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabMergeRequestWrapper.java b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabMergeRequestWrapper.java index ba4a0b1..a8af395 100755 --- a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabMergeRequestWrapper.java +++ b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabMergeRequestWrapper.java @@ -102,10 +102,10 @@ public void check(GitlabMergeRequest gitlabMergeRequest) { GitlabAPI api = builder.getGitlab().get(); GitlabCommit latestCommit = getLatestCommit(gitlabMergeRequest, api); - if (latestCommit == null) { // the source branch has been removed + if (latestCommit == null) { // the source branch has been removed and is not merged return; } - + Map customParameters = getSpecifiedCustomParameters(gitlabMergeRequest, api); build(customParameters, latestCommit.getId(), gitlabMergeRequest); } catch (IOException e) { @@ -156,7 +156,21 @@ public int compare(GitlabCommit o1, GitlabCommit o2) { if (commits.isEmpty()) { LOGGER.log(Level.SEVERE, "Merge Request without commits."); - return null; + if (gitlabMergeRequest.isMerged()) { + // get target branch latest commit id + commits = api.getLastCommits(gitlabMergeRequest.getTargetProjectId(), gitlabMergeRequest.getTargetBranch()); + Collections.sort(commits, new Comparator() { + public int compare(GitlabCommit o1, GitlabCommit o2) { + return o2.getCreatedAt().compareTo(o1.getCreatedAt()); + } + }); + if (commits.isEmpty()) { + LOGGER.log(Level.SEVERE, "Merge Request's project branch has no commits."); + return null; + } + } else { + return null; + } } return commits.get(0); @@ -206,29 +220,30 @@ public String getTargetBranch() { return targetBranch; } - public GitlabNote createNote(String message, boolean shouldClose, boolean shouldMerge) { + public static GitlabNote createNote(Integer id, Integer iid, Integer pid, String message, boolean shouldClose, boolean shouldMerge) { GitlabMergeRequest mergeRequest = new GitlabMergeRequest(); mergeRequest.setId(id); mergeRequest.setIid(iid); - mergeRequest.setProjectId(project.getId()); + mergeRequest.setProjectId(pid); + Gitlab gitlab = GitlabBuildTrigger.DESCRIPTOR.getGitlab(); try { if (shouldClose || shouldMerge) { String tailUrl = ""; if (shouldClose) { - tailUrl = GitlabProject.URL + "/" + project.getId() + "/merge_request/" + iid + "?state_event=close"; + tailUrl = GitlabProject.URL + "/" + pid + "/merge_requests/" + iid + "?state_event=close"; } if (shouldMerge) { - tailUrl = GitlabProject.URL + "/" + project.getId() + "/merge_request/" + iid + "/merge"; + tailUrl = GitlabProject.URL + "/" + pid + "/merge_requests/" + iid + "/merge"; } - builder.getGitlab().get().retrieve().method("PUT").to(tailUrl, Void.class); + gitlab.get().retrieve().method("PUT").to(tailUrl, Void.class); } } catch (IOException e) { LOGGER.log(Level.SEVERE, "Failed to automatically merge/close the merge request " + iid, e); } try { - return builder.getGitlab().get().createNote(mergeRequest, message); + return gitlab.get().createNote(mergeRequest, message); } catch (IOException e) { LOGGER.log(Level.SEVERE, "Failed to create note for merge request " + iid, e); return null; @@ -236,24 +251,27 @@ public GitlabNote createNote(String message, boolean shouldClose, boolean should } - public GitlabCommitStatus changeCommitStatus(String commitHash, String commitStatus, String targetUrl) { - - try { - GitlabAPI api = builder.getGitlab().get(); - GitlabMergeRequest mergeRequest = api.getMergeRequest(project, iid); - - return builder.getGitlab().changeCommitStatus(project.getId(), mergeRequest.getSourceBranch(), commitHash, commitStatus, targetUrl); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Failed to change status for merge request commit " + commitHash, e); - } - - return null; - } +// public GitlabCommitStatus changeCommitStatus(String commitHash, String commitStatus, String targetUrl) { +// +// try { +// GitlabAPI api = builder.getGitlab().get(); +// GitlabMergeRequest mergeRequest = api.getMergeRequest(project, iid); +// +// return builder.getGitlab().changeCommitStatus(project.getId(), mergeRequest.getSourceBranch(), commitHash, commitStatus, targetUrl); +// } catch (IOException e) { +// LOGGER.log(Level.SEVERE, "Failed to change status for merge request commit " + commitHash, e); +// } +// +// return null; +// } private void build(Map customParameters, String commitHash, GitlabMergeRequest mergeRequest) { GitlabCause cause = new GitlabCause( this.getId(), this.getIid(), + mergeRequest.getState(), + mergeRequest.getAuthor().getEmail(), + mergeRequest.getAssignee().getEmail(), this.getSourceName(), this.getSourceRepository(), this.getSourceBranch(), @@ -263,19 +281,24 @@ private void build(Map customParameters, String commitHash, Gitl this.getDescription(), this.sourceProject.getId(), project.getId(), - commitHash); + commitHash, + mergeRequest.getWebUrl()); try { + cause.setTrigger(builder.getTrigger()); + String message = builder.getBuilds().build(cause, customParameters, project, mergeRequest); if (builder.isEnableBuildTriggeredMessage() && StringUtils.isNotBlank(message)) { - createNote(message, false, false); + GitlabMergeRequestWrapper.createNote(this.id, this.iid, this.project.getId(), message, false, false); LOGGER.log(Level.INFO, message); } } catch (IOException e) { - // TODO Auto-generated catch block e.printStackTrace(); } } + public GitlabProject getProject() { + return project; + } } diff --git a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabQueueListener.java b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabQueueListener.java index c6c54ac..be657e3 100755 --- a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabQueueListener.java +++ b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabQueueListener.java @@ -1,6 +1,7 @@ package org.jenkinsci.plugins.gitlab; import java.io.IOException; +import java.util.logging.Level; import java.util.logging.Logger; import jenkins.model.Jenkins; @@ -8,24 +9,28 @@ import hudson.model.Cause; import hudson.model.Queue; import hudson.model.queue.QueueListener; +import org.gitlab.api.models.GitlabMergeRequest; @Extension public class GitlabQueueListener extends QueueListener { private static final Logger LOGGER = Logger.getLogger(GitlabQueueListener.class.getName()); - public void onEnterWaiting(Queue.WaitingItem wi) { - for (Cause c : wi.getCauses()) { + public void onEnterBuildable(Queue.BuildableItem bi) { + for (Cause c : bi.getCauses()) { if (c instanceof GitlabCause) { - Gitlab gitlab = new Gitlab(); - GitlabCause cause = (GitlabCause) c; - Jenkins instance = Jenkins.getInstance(); - String rootUrl = instance == null ? "/" : instance.getRootUrl(); - String url = rootUrl + wi.getUrl(); - try { - gitlab.changeCommitStatus(cause.getTargetProjectId(), cause.getSourceBranch(), cause.getLastCommitId(), "pending", url); - } catch (IOException e) { - LOGGER.info("error trying to set pending status"); + if (((GitlabCause) c).getMergeRequestState().equals(GitlabMergeRequest.STATUS_OPENED)) { + Gitlab gitlab = GitlabBuildTrigger.DESCRIPTOR.getGitlab(); + GitlabCause cause = (GitlabCause) c; + Jenkins instance = Jenkins.getInstance(); + String rootUrl = instance == null ? "/" : instance.getRootUrl(); + String url = rootUrl + bi.getUrl(); + try { + LOGGER.log(Level.INFO, "Send pending status to commit: " + cause.getLastCommitId()); + gitlab.changeCommitStatus(cause.getTargetProjectId(), cause.getSourceBranch(), cause.getLastCommitId(), "pending", url); + } catch (IOException e) { + LOGGER.info("error trying to set pending status"); + } } } } diff --git a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabRepository.java b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabRepository.java index 0a4578c..4348c28 100755 --- a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabRepository.java +++ b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabRepository.java @@ -105,33 +105,33 @@ private GitlabProject getProjectForPath(String path) { return null; } - public String getProjectUrl() { - try { - return builder.getGitlab().get().getUrl(project.getPathWithNamespace()).toString(); - } catch (IOException e) { - return null; - } - } - - public String getMergeRequestUrl(Integer mergeRequestIid) { - return getProjectUrl() + GitlabMergeRequest.URL + "/" + mergeRequestIid; - } - - public GitlabNote createNote(Integer mergeRequestId, String message, boolean shouldClose, boolean shouldMerge) { - GitlabMergeRequestWrapper gitlabMergeRequestWrapper = mergeRequests.get(mergeRequestId); - return gitlabMergeRequestWrapper.createNote(message, shouldClose, shouldMerge); - } - - public GitlabCommitStatus changeCommitStatus(Integer mergeRequestId, String commitHash, String commitStatus, String targetUrl) { - if (commitHash != null) { - - GitlabMergeRequestWrapper gitlabMergeRequestWrapper = mergeRequests.get(mergeRequestId); - - LOGGER.info("Sending Status: " + commitStatus); - - return gitlabMergeRequestWrapper.changeCommitStatus(commitHash, commitStatus, targetUrl); - } else { - return null; - } - } +// public String getProjectUrl() { +// try { +// return builder.getGitlab().get().getUrl(project.getPathWithNamespace()).toString(); +// } catch (IOException e) { +// return null; +// } +// } + +// public String getMergeRequestUrl(Integer mergeRequestIid) { +// return getProjectUrl() + GitlabMergeRequest.URL + "/" + mergeRequestIid; +// } +// +// public GitlabNote createNote(Integer mergeRequestId, String message, boolean shouldClose, boolean shouldMerge) { +// GitlabMergeRequestWrapper wrapper = mergeRequests.get(mergeRequestId); +// return GitlabMergeRequestWrapper.createNote(wrapper.getId(), wrapper.getIid(), wrapper.getProject().getId(), message, shouldClose, shouldMerge); +// } + +// public GitlabCommitStatus changeCommitStatus(Integer mergeRequestId, String commitHash, String commitStatus, String targetUrl) { +// if (commitHash != null) { +// +// GitlabMergeRequestWrapper gitlabMergeRequestWrapper = mergeRequests.get(mergeRequestId); +// +// LOGGER.info("Sending Status: " + commitStatus); +// +// return gitlabMergeRequestWrapper.changeCommitStatus(commitHash, commitStatus, targetUrl); +// } else { +// return null; +// } +// } } diff --git a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabWebhooks.java b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabWebhooks.java index f60b270..9de41a1 100755 --- a/src/main/java/org/jenkinsci/plugins/gitlab/GitlabWebhooks.java +++ b/src/main/java/org/jenkinsci/plugins/gitlab/GitlabWebhooks.java @@ -4,9 +4,11 @@ import hudson.Extension; import hudson.model.UnprotectedRootAction; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; import org.gitlab.api.GitlabAPI; import org.gitlab.api.models.GitlabMergeRequest; import org.gitlab.api.models.GitlabProject; +import org.gitlab.api.models.GitlabUser; import org.jenkinsci.plugins.gitlab.models.webhook.MergeRequest; import org.jenkinsci.plugins.gitlab.models.webhook.Note; import org.jenkinsci.plugins.gitlab.models.webhook.OnlyType; @@ -66,7 +68,7 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod }; try { String requestBodyString = IOUtils.toString(request.getInputStream(), "UTF-8"); - LOGGER.fine(requestBodyString); +// LOGGER.info(requestBodyString); OnlyType hookObjectKind = OnlyType.fromJson(requestBodyString); MergeRequest mergeRequest = null; switch (hookObjectKind.object_kind) { @@ -79,13 +81,27 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod break; default: {} } - LOGGER.fine(String.format("MergeRequest is %s", mergeRequest)); + LOGGER.info(String.format("MergeRequest is %s", mergeRequest)); GitlabBuildTrigger trigger = mergeRequest != null ? findTrigger(mergeRequest) : null; if (trigger != null) { GitlabMergeRequestBuilder currentBuilder = trigger.getBuilder(); GitlabAPI api = currentBuilder.getGitlab().get(); GitlabProject project = api.getProject(mergeRequest.getTarget_project_id()); - GitlabMergeRequest gitlabMergeRequest = api.getMergeRequest(project, mergeRequest.getId()); + GitlabMergeRequest gitlabMergeRequest = api.getMergeRequest(project, mergeRequest.getIid()); + // make sure author email exists + GitlabUser author = gitlabMergeRequest.getAuthor(); + GitlabUser assignee = gitlabMergeRequest.getAssignee(); + if (StringUtils.isEmpty(author.getEmail())) { + String tailUrl = GitlabUser.URL + "/" + author.getId(); + author = api.getUser(author.getId()); + gitlabMergeRequest.getAuthor().setEmail(author.getEmail()); + } + if (StringUtils.isEmpty(assignee.getEmail())) { + String tailUrl = GitlabUser.URL + "/" + assignee.getId(); + assignee = api.getUser(assignee.getId()); + gitlabMergeRequest.getAssignee().setEmail(assignee.getEmail()); + } + LOGGER.info(String.format("MergeRequest %s author is %s:%s, assignee %s:%s", author.getId(), author.getName(), author.getEmail(), assignee.getName(), assignee.getEmail())); GitlabMergeRequestWrapper mergeRequestWrapper; Map mergeRequestWrapperMap = currentBuilder.getMergeRequests(); @@ -105,12 +121,12 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod } } catch (IOException ex) { - LOGGER.severe("There was an error"); + LOGGER.severe("There was an error: " + ex.toString()); LOGGER.throwing("GitlabWebhooks", "doStart", ex); } catch (JsonSyntaxException e) { LOGGER.warning(e.toString()); } catch (Exception e) { - LOGGER.severe(String.format("%s on run doStart", e)); + LOGGER.throwing("GitlabWebhooks", "doStart", e); } return response; } diff --git a/src/main/java/org/jenkinsci/plugins/gitlab/models/webhook/BuildState.java b/src/main/java/org/jenkinsci/plugins/gitlab/models/webhook/BuildState.java new file mode 100644 index 0000000..849bc6e --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/gitlab/models/webhook/BuildState.java @@ -0,0 +1,13 @@ +package org.jenkinsci.plugins.gitlab.models.webhook; +/* + * + * Edward Chen + * edward_chen@gemdata.net + * 2019-07-22 15:04 + * + * Copyright (c) 2016-2018, GemData. All Right Reserved, http://www.gemdata.net + */ + +public enum BuildState { + pending, running, canceled, success, failed +} diff --git a/src/main/resources/META-INF/hudson.remoting.ClassFilter b/src/main/resources/META-INF/hudson.remoting.ClassFilter new file mode 100644 index 0000000..67437a4 --- /dev/null +++ b/src/main/resources/META-INF/hudson.remoting.ClassFilter @@ -0,0 +1,6 @@ +org.gitlab.api.models.GitlabProject +org.gitlab.api.models.GitlabNamespace +org.gitlab.api.models.GitlabPermission +org.gitlab.api.models.GitlabUser +org.gitlab.api.models.GitlabProjectAccessLevel +org.gitlab.api.models.GitlabProjectSharedGroup \ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/gitlab/GitlabBuildTrigger/config.jelly b/src/main/resources/org/jenkinsci/plugins/gitlab/GitlabBuildTrigger/config.jelly index 008bab5..5fe805c 100644 --- a/src/main/resources/org/jenkinsci/plugins/gitlab/GitlabBuildTrigger/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/gitlab/GitlabBuildTrigger/config.jelly @@ -4,9 +4,13 @@ description="The full path including namespace to the project"> + + + - + diff --git a/src/main/resources/org/jenkinsci/plugins/gitlab/GitlabBuildTrigger/global.jelly b/src/main/resources/org/jenkinsci/plugins/gitlab/GitlabBuildTrigger/global.jelly index 04fcac6..61073d2 100755 --- a/src/main/resources/org/jenkinsci/plugins/gitlab/GitlabBuildTrigger/global.jelly +++ b/src/main/resources/org/jenkinsci/plugins/gitlab/GitlabBuildTrigger/global.jelly @@ -14,7 +14,7 @@ - + diff --git a/src/main/resources/org/jenkinsci/plugins/gitlab/GitlabMergeRequestAddCommentStep/config.jelly b/src/main/resources/org/jenkinsci/plugins/gitlab/GitlabMergeRequestAddCommentStep/config.jelly new file mode 100644 index 0000000..081a387 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/gitlab/GitlabMergeRequestAddCommentStep/config.jelly @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/main/resources/org/jenkinsci/plugins/gitlab/GitlabMergeRequestCommitStatusUpdaterStep/config.jelly b/src/main/resources/org/jenkinsci/plugins/gitlab/GitlabMergeRequestCommitStatusUpdaterStep/config.jelly new file mode 100644 index 0000000..bece8c3 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/gitlab/GitlabMergeRequestCommitStatusUpdaterStep/config.jelly @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/java/com/jenkinsci/plugins/gitlab/GitlabBuilds_build_Test.java b/src/test/java/com/jenkinsci/plugins/gitlab/GitlabBuilds_build_Test.java index 72c48dd..9ee7879 100755 --- a/src/test/java/com/jenkinsci/plugins/gitlab/GitlabBuilds_build_Test.java +++ b/src/test/java/com/jenkinsci/plugins/gitlab/GitlabBuilds_build_Test.java @@ -36,8 +36,10 @@ public class GitlabBuilds_build_Test { GitlabProject project; @Injectable GitlabUser user; - @Injectable - GitlabMergeRequest mergeRequest; + + //@Injectable + + GitlabMergeRequest mergeRequest = new GitlabMergeRequest(); @Injectable GitlabBuildTrigger trigger; @@ -47,10 +49,12 @@ public class GitlabBuilds_build_Test { @Tested GitlabBuilds subject; - GitlabCause cause = new GitlabCause( 1, 2, + "opened", + "authorEmail", + "assigneeEmail", "sourceName", "sourceRepo", "sourceBranch", @@ -60,10 +64,12 @@ public class GitlabBuilds_build_Test { "description", 3, 4, - "commitHash" + "commitHash", + "http://web_url" ); - List statuses = Arrays.asList(new GitlabCommitStatus()); + GitlabCommitStatus status = new GitlabCommitStatus(); + List statuses = Arrays.asList(status); @BeforeClass public static void beforeClass() { @@ -84,6 +90,8 @@ Secret fromString(String data) { @Before public void before() throws Exception { + status.setStatus("running"); + user.setUsername("username"); mergeRequest.setAssignee(user); @@ -107,12 +115,10 @@ public void build() throws IOException { } @Test - public void doesNotBuild_branchPattern() throws IOException { + public void doesNotBuild_MergeRequestClosed() throws IOException { - new NonStrictExpectations() {{ - trigger.getTargetBranchRegex(); - result = "thisisafakepattern"; - }}; + String stateStr = mergeRequest.getState(); + mergeRequest.setState("closed"); subject.build(cause, new HashMap(), project, mergeRequest); @@ -120,15 +126,15 @@ public void doesNotBuild_branchPattern() throws IOException { trigger.startJob((GitlabCause) any); times = 0; }}; + + mergeRequest.setState(stateStr); } @Test - public void doesNotBuild_hasCommitStatus() throws IOException { + public void doesNotBuild_MergeRequestMerged() throws IOException { - new NonStrictExpectations() {{ - api.getCommitStatuses(project, cause.getLastCommitId()); - result = statuses; - }}; + String stateStr = mergeRequest.getState(); + mergeRequest.setState("merged"); subject.build(cause, new HashMap(), project, mergeRequest); @@ -136,14 +142,16 @@ public void doesNotBuild_hasCommitStatus() throws IOException { trigger.startJob((GitlabCause) any); times = 0; }}; + + mergeRequest.setState(stateStr); } @Test - public void doesNotBuild_notMatchingAssigneeFilter() throws IOException { + public void doesNotBuild_SourceBranchPattern() throws IOException { new NonStrictExpectations() {{ - trigger.getAssigneeFilter(); - result = "jenkins"; + trigger.getSourceBranchRegex(); + result = "thisisafakepattern"; }}; subject.build(cause, new HashMap(), project, mergeRequest); @@ -155,11 +163,11 @@ public void doesNotBuild_notMatchingAssigneeFilter() throws IOException { } @Test - public void doesNotBuild_notMatchingTagFilter() throws IOException { + public void doesNotBuild_TargetBranchPattern() throws IOException { new NonStrictExpectations() {{ - trigger.getTagFilter(); - result = "Build"; + trigger.getTargetBranchRegex(); + result = "thisisafakepattern"; }}; subject.build(cause, new HashMap(), project, mergeRequest); @@ -171,123 +179,171 @@ public void doesNotBuild_notMatchingTagFilter() throws IOException { } @Test - public void onStart_notMuted(@Mocked final AbstractBuild build) { - - new NonStrictExpectations(subject) {{ - invoke(subject, "getCause", (AbstractBuild) build); - result = cause; - - invoke(subject, "getRootUrl"); - result = "http://git.example.com"; - - invoke(subject, "isPublishBuildProgressMessages"); - result = true; - }}; - - subject.onStarted(build); - - new Verifications() {{ - repository.createNote(anyInt, anyString, anyBoolean, anyBoolean); - times = 1; - }}; - } - - @Test - public void onStart_muted(@Mocked final AbstractBuild build) { - - new NonStrictExpectations(subject) {{ - invoke(subject, "getCause", (AbstractBuild) build); - result = cause; - - invoke(subject, "getRootUrl"); - result = "http://git.example.com"; + public void doesNotBuild_hasCommitStatus() throws IOException { - invoke(subject, "isPublishBuildProgressMessages"); - result = false; + new NonStrictExpectations() {{ + api.getCommitStatuses(project, cause.getLastCommitId()); + result = statuses; }}; - subject.onStarted(build); + subject.build(cause, new HashMap(), project, mergeRequest); new Verifications() {{ - repository.createNote(anyInt, anyString, anyBoolean, anyBoolean); + trigger.startJob((GitlabCause) any); times = 0; }}; } @Test - public void onCompleted_notMuted(@Mocked final AbstractBuild build) { - - new NonStrictExpectations(subject) {{ - invoke(subject, "getCause", (AbstractBuild) build); - result = cause; - - invoke(subject, "getResult", (AbstractBuild) build); - result = Result.SUCCESS; - - invoke(subject, "getRootUrl"); - result = "http://git.example.com"; + public void doesNotBuild_notMatchingAssigneeFilter() throws IOException { - invoke(subject, "isPublishBuildProgressMessages"); - result = true; + new NonStrictExpectations() {{ + trigger.getAssigneeFilter(); + result = "jenkins"; }}; - subject.onCompleted(build); + subject.build(cause, new HashMap(), project, mergeRequest); new Verifications() {{ - repository.createNote(anyInt, anyString, anyBoolean, anyBoolean); - times = 1; + trigger.startJob((GitlabCause) any); + times = 0; }}; } @Test - public void onCompleted_muted(@Mocked final AbstractBuild build) { - - new NonStrictExpectations(subject) {{ - invoke(subject, "getCause", (AbstractBuild) build); - result = cause; - - invoke(subject, "getResult", (AbstractBuild) build); - result = Result.SUCCESS; - - invoke(subject, "getRootUrl"); - result = "http://git.example.com"; + public void doesNotBuild_notMatchingTagFilter() throws IOException { - invoke(subject, "isPublishBuildProgressMessages"); - result = false; + new NonStrictExpectations() {{ + trigger.getTagFilter(); + result = "Build"; }}; - subject.onCompleted(build); + subject.build(cause, new HashMap(), project, mergeRequest); new Verifications() {{ - repository.createNote(anyInt, anyString, anyBoolean, anyBoolean); + trigger.startJob((GitlabCause) any); times = 0; }}; } - @Test - public void onCompleted_mutedButBuildFailed(@Mocked final AbstractBuild build) { - - new NonStrictExpectations(subject) {{ - invoke(subject, "getCause", (AbstractBuild) build); - result = cause; - - invoke(subject, "getResult", (AbstractBuild) build); - result = Result.FAILURE; - - invoke(subject, "getRootUrl"); - result = "http://git.example.com"; - - invoke(subject, "isPublishBuildProgressMessages"); - result = false; - }}; - - subject.onCompleted(build); - - new Verifications() {{ - repository.createNote(anyInt, anyString, anyBoolean, anyBoolean); - times = 1; - }}; - } +// @Test +// public void onStart_notMuted(@Mocked final AbstractBuild build) { +// +// new NonStrictExpectations(subject) {{ +// invoke(subject, "getCause", (AbstractBuild) build); +// result = cause; +// +// invoke(subject, "getRootUrl"); +// result = "http://git.example.com"; +// +// invoke(subject, "isPublishBuildProgressMessages"); +// result = true; +// }}; +// +// subject.onStarted(build); +// +// new Verifications() {{ +// repository.createNote(anyInt, anyString, anyBoolean, anyBoolean); +// times = 1; +// }}; +// } +// +// @Test +// public void onStart_muted(@Mocked final AbstractBuild build) { +// +// new NonStrictExpectations(subject) {{ +// invoke(subject, "getCause", (AbstractBuild) build); +// result = cause; +// +// invoke(subject, "getRootUrl"); +// result = "http://git.example.com"; +// +// invoke(subject, "isPublishBuildProgressMessages"); +// result = false; +// }}; +// +// subject.onStarted(build); +// +// new Verifications() {{ +// repository.createNote(anyInt, anyString, anyBoolean, anyBoolean); +// times = 0; +// }}; +// } + +// @Test +// public void onCompleted_notMuted(@Mocked final AbstractBuild build) { +// +// new NonStrictExpectations(subject) {{ +// invoke(subject, "getCause", (AbstractBuild) build); +// result = cause; +// +// invoke(subject, "getResult", (AbstractBuild) build); +// result = Result.SUCCESS; +// +// invoke(subject, "getRootUrl"); +// result = "http://git.example.com"; +// +// invoke(subject, "isPublishBuildProgressMessages"); +// result = true; +// }}; +// +// subject.onCompleted(build); +// +// new Verifications() {{ +// repository.createNote(anyInt, anyString, anyBoolean, anyBoolean); +// times = 1; +// }}; +// } +// +// @Test +// public void onCompleted_muted(@Mocked final AbstractBuild build) { +// +// new NonStrictExpectations(subject) {{ +// invoke(subject, "getCause", (AbstractBuild) build); +// result = cause; +// +// invoke(subject, "getResult", (AbstractBuild) build); +// result = Result.SUCCESS; +// +// invoke(subject, "getRootUrl"); +// result = "http://git.example.com"; +// +// invoke(subject, "isPublishBuildProgressMessages"); +// result = false; +// }}; +// +// subject.onCompleted(build); +// +// new Verifications() {{ +// repository.createNote(anyInt, anyString, anyBoolean, anyBoolean); +// times = 0; +// }}; +// } + +// @Test +// public void onCompleted_mutedButBuildFailed(@Mocked final AbstractBuild build) { +// +// new NonStrictExpectations(subject) {{ +// invoke(subject, "getCause", (AbstractBuild) build); +// result = cause; +// +// invoke(subject, "getResult", (AbstractBuild) build); +// result = Result.FAILURE; +// +// invoke(subject, "getRootUrl"); +// result = "http://git.example.com"; +// +// invoke(subject, "isPublishBuildProgressMessages"); +// result = false; +// }}; +// +// subject.onCompleted(build); +// +// new Verifications() {{ +// repository.createNote(anyInt, anyString, anyBoolean, anyBoolean); +// times = 1; +// }}; +// } @Test public void WorkInProgressRespect()