Merge branch 'master' of gitee.com:oschina/Gitee-Jenkins-Plugin into ISSUE#I2BALI

This commit is contained in:
silverballer 2020-12-30 16:38:35 +08:00 committed by Gitee
commit 8f500cfb67
30 changed files with 425 additions and 90 deletions

View File

@ -29,7 +29,7 @@ Gitee Jenkins Plugin 是码云基于 [GitLab Plugin](https://github.com/jenkinsc
## 目前支持特性: ## 目前支持特性:
- 推送代码到码云时,由配置的 WebHook 触发 Jenkins 任务构建。 - 推送代码到码云时,由配置的 WebHook 触发 Jenkins 任务构建。
- 提交 Pull Request 到码云项目时,由配置的 WebHook 触发 Jenkins 任务构建支持PR动作新建更新接受关闭审查通过测试通过。 - 提交 Pull Request 到码云项目时,由配置的 WebHook 触发 Jenkins 任务构建支持PR动作新建更新接受关闭审查通过测试通过。
- 支持 [ci-skip] 指令过滤。 - 支持 [ci-skip] 指令过滤 或者 [ci-build] 指令触发构建
- 过滤已经构建的 Commit 版本,若是分支 Push则相同分支Push才过滤若是 PR则是同一个PR才过滤。 - 过滤已经构建的 Commit 版本,若是分支 Push则相同分支Push才过滤若是 PR则是同一个PR才过滤。
- 按分支名过滤触发器。 - 按分支名过滤触发器。
- 正则表达式过滤可触发的分支。 - 正则表达式过滤可触发的分支。
@ -39,6 +39,7 @@ Gitee Jenkins Plugin 是码云基于 [GitLab Plugin](https://github.com/jenkinsc
- 对于 PR 相关的所有事件,若 PR 代码冲突不可自动合并则不触发构建且若配置了评论到PR的功能则评论到 PR 提示冲突。 - 对于 PR 相关的所有事件,若 PR 代码冲突不可自动合并则不触发构建且若配置了评论到PR的功能则评论到 PR 提示冲突。
- PR 评论可通过 WebHook 触发构建(可用于 PR 触发构建失败是便于从码云平台评论重新触发构建) - PR 评论可通过 WebHook 触发构建(可用于 PR 触发构建失败是便于从码云平台评论重新触发构建)
- 支持配置 PR 不要求必须测试时过滤触发构建。(可用于不需测试则不构建部署测试环境) - 支持配置 PR 不要求必须测试时过滤触发构建。(可用于不需测试则不构建部署测试环境)
- 支持相同 PR 触发构建时,取消进行中的未完成构建,进行当前构建(相同 PR 构建不排队,多个不同 PR 构建仍需排队)
## 计划中特性 ## 计划中特性
1. PR 审查并测试通过触发构建(可用户触发部署,且可配合自动合并 PR 的特性完善工作流。) 1. PR 审查并测试通过触发构建(可用户触发部署,且可配合自动合并 PR 的特性完善工作流。)

View File

@ -531,6 +531,11 @@ public final class CauseData {
data.getTargetProjectUrl()); data.getTargetProjectUrl());
} }
} }
}, COMMIT_COMMENT {
@Override
String getShortDescription(CauseData data) {
return Messages.GiteeWebHookCause_ShortDescription_Commit_comment(data.getTriggeredByUser());
}
}, PIPELINE { }, PIPELINE {
@Override @Override
String getShortDescription(CauseData data) { String getShortDescription(CauseData data) {

View File

@ -58,6 +58,11 @@ public class NoteHook extends WebHook {
} }
public String getWebHookDescription() { public String getWebHookDescription() {
// 兼容commit评论
if (pullRequest == null) {
return getHookName() + " commit sha = " + comment.getCommitId();
}
return getHookName() + " iid = " + pullRequest.getNumber() + " merge commit sha = " + pullRequest.getMergeCommitSha(); return getHookName() + " iid = " + pullRequest.getNumber() + " merge commit sha = " + pullRequest.getMergeCommitSha();
} }

View File

@ -20,6 +20,8 @@ public class NoteObjectAttributes {
private Date createdAt; private Date createdAt;
private Date updatedAt; private Date updatedAt;
private String htmlUrl; private String htmlUrl;
private String commitId;
private User user;
public Integer getId() { public Integer getId() {
return id; return id;
@ -77,6 +79,22 @@ public class NoteObjectAttributes {
this.htmlUrl = htmlUrl; this.htmlUrl = htmlUrl;
} }
public String getCommitId() {
return commitId;
}
public void setCommitId(String commitId) {
this.commitId = commitId;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {
@ -87,39 +105,45 @@ public class NoteObjectAttributes {
} }
NoteObjectAttributes that = (NoteObjectAttributes) o; NoteObjectAttributes that = (NoteObjectAttributes) o;
return new EqualsBuilder() return new EqualsBuilder()
.append(id, that.id) .append(id, that.id)
.append(body, that.body) .append(body, that.body)
.append(projectId, that.projectId) .append(projectId, that.projectId)
.append(authorId, that.authorId) .append(authorId, that.authorId)
.append(createdAt, that.createdAt) .append(createdAt, that.createdAt)
.append(updatedAt, that.updatedAt) .append(updatedAt, that.updatedAt)
.append(htmlUrl, that.htmlUrl) .append(htmlUrl, that.htmlUrl)
.isEquals(); .append(commitId, that.commitId)
.append(user, that.user)
.isEquals();
} }
@Override @Override
public int hashCode() { public int hashCode() {
return new HashCodeBuilder(17, 37) return new HashCodeBuilder(17, 37)
.append(id) .append(id)
.append(body) .append(body)
.append(projectId) .append(projectId)
.append(authorId) .append(authorId)
.append(createdAt) .append(createdAt)
.append(updatedAt) .append(updatedAt)
.append(htmlUrl) .append(htmlUrl)
.toHashCode(); .append(commitId)
.append(user)
.toHashCode();
} }
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this) return new ToStringBuilder(this)
.append("id", id) .append("id", id)
.append("body", body) .append("body", body)
.append("projectId", projectId) .append("projectId", projectId)
.append("authorId", authorId) .append("authorId", authorId)
.append("createdAt", createdAt) .append("createdAt", createdAt)
.append("updatedAt", updatedAt) .append("updatedAt", updatedAt)
.append("htmlUrl", htmlUrl) .append("htmlUrl", htmlUrl)
.toString(); .append("commitId", commitId)
.append("user", user)
.toString();
} }
} }

View File

@ -111,10 +111,6 @@ public class PushHook extends WebHook {
this.project = project; this.project = project;
} }
public void setRepository(Project project) {
this.project = project;
}
public List<Commit> getCommits() { public List<Commit> getCommits() {
return commits; return commits;
} }

View File

@ -74,7 +74,8 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
private boolean triggerOnTestedPullRequest = false; private boolean triggerOnTestedPullRequest = false;
private boolean triggerOnNoteRequest = true; private boolean triggerOnNoteRequest = true;
private String noteRegex = ""; private String noteRegex = "";
private boolean ciSkip = true; private transient boolean ciSkip = true;
private BuildInstructionFilterType buildInstructionFilterType;
private boolean skipWorkInProgressPullRequest; private boolean skipWorkInProgressPullRequest;
private boolean ciSkipFroTestNotRequired; private boolean ciSkipFroTestNotRequired;
private boolean skipLastCommitHasBeenBuild; private boolean skipLastCommitHasBeenBuild;
@ -92,6 +93,7 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
private volatile Secret secretToken; private volatile Secret secretToken;
private String pendingBuildName; private String pendingBuildName;
private boolean cancelPendingBuildsOnUpdate; private boolean cancelPendingBuildsOnUpdate;
private boolean cancelIncompleteBuildOnSamePullRequest;
private transient BranchFilter branchFilter; private transient BranchFilter branchFilter;
private transient PushHookTriggerHandler pushHookTriggerHandler; private transient PushHookTriggerHandler pushHookTriggerHandler;
@ -113,11 +115,13 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
boolean triggerOnClosedPullRequest, boolean triggerOnClosedPullRequest,
boolean triggerOnNoteRequest, String noteRegex, boolean triggerOnNoteRequest, String noteRegex,
boolean skipWorkInProgressPullRequest, boolean ciSkip, boolean skipWorkInProgressPullRequest, boolean ciSkip,
BuildInstructionFilterType buildInstructionFilterType,
boolean setBuildDescription, boolean addNoteOnPullRequest, boolean addCiMessage, boolean addVoteOnPullRequest, boolean setBuildDescription, boolean addNoteOnPullRequest, boolean addCiMessage, boolean addVoteOnPullRequest,
boolean acceptPullRequestOnSuccess, BranchFilterType branchFilterType, boolean acceptPullRequestOnSuccess, BranchFilterType branchFilterType,
String includeBranchesSpec, String excludeBranchesSpec, String targetBranchRegex, String includeBranchesSpec, String excludeBranchesSpec, String targetBranchRegex,
PullRequestLabelFilterConfig pullRequestLabelFilterConfig, String secretToken, boolean triggerOnPipelineEvent, PullRequestLabelFilterConfig pullRequestLabelFilterConfig, String secretToken, boolean triggerOnPipelineEvent,
boolean triggerOnApprovedPullRequest, String pendingBuildName, boolean cancelPendingBuildsOnUpdate) { boolean triggerOnApprovedPullRequest, String pendingBuildName, boolean cancelPendingBuildsOnUpdate,
boolean cancelIncompleteBuildOnSamePullRequest) {
this.triggerOnPush = triggerOnPush; this.triggerOnPush = triggerOnPush;
this.triggerOnOpenPullRequest = triggerOnOpenPullRequest; this.triggerOnOpenPullRequest = triggerOnOpenPullRequest;
this.triggerOnUpdatePullRequest = triggerOnUpdatePullRequest; this.triggerOnUpdatePullRequest = triggerOnUpdatePullRequest;
@ -127,6 +131,7 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
this.noteRegex = noteRegex; this.noteRegex = noteRegex;
this.triggerOnPipelineEvent = triggerOnPipelineEvent; this.triggerOnPipelineEvent = triggerOnPipelineEvent;
this.ciSkip = ciSkip; this.ciSkip = ciSkip;
this.buildInstructionFilterType = buildInstructionFilterType;
this.skipWorkInProgressPullRequest = skipWorkInProgressPullRequest; this.skipWorkInProgressPullRequest = skipWorkInProgressPullRequest;
this.setBuildDescription = setBuildDescription; this.setBuildDescription = setBuildDescription;
this.addNoteOnPullRequest = addNoteOnPullRequest; this.addNoteOnPullRequest = addNoteOnPullRequest;
@ -142,6 +147,7 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
this.triggerOnApprovedPullRequest = triggerOnApprovedPullRequest; this.triggerOnApprovedPullRequest = triggerOnApprovedPullRequest;
this.pendingBuildName = pendingBuildName; this.pendingBuildName = pendingBuildName;
this.cancelPendingBuildsOnUpdate = cancelPendingBuildsOnUpdate; this.cancelPendingBuildsOnUpdate = cancelPendingBuildsOnUpdate;
this.cancelIncompleteBuildOnSamePullRequest = cancelIncompleteBuildOnSamePullRequest;
initializeTriggerHandler(); initializeTriggerHandler();
initializeBranchFilter(); initializeBranchFilter();
@ -193,6 +199,24 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
oldConfig.jobsMigrated2 = true; oldConfig.jobsMigrated2 = true;
oldConfig.save(); oldConfig.save();
} }
// 兼容构建指令升级
if (!oldConfig.jobsMigrated3) {
for (AbstractProject<?, ?> project : Jenkins.getInstance().getAllItems(AbstractProject.class)) {
GiteePushTrigger trigger = project.getTrigger(GiteePushTrigger.class);
if (trigger != null) {
if (trigger.getCiSkip()) {
trigger.setBuildInstructionFilterType(BuildInstructionFilterType.CI_SKIP);
} else {
trigger.setBuildInstructionFilterType(BuildInstructionFilterType.NONE);
}
project.save();
}
}
oldConfig.jobsMigrated3 = true;
oldConfig.save();
}
} }
public boolean getAddNoteOnPullRequest() { return addNoteOnPullRequest; } public boolean getAddNoteOnPullRequest() { return addNoteOnPullRequest; }
@ -219,8 +243,8 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
public boolean isTriggerOnApprovedPullRequest() { public boolean isTriggerOnApprovedPullRequest() {
return triggerOnApprovedPullRequest; return triggerOnApprovedPullRequest;
} }
public boolean isTriggerOnClosedPullRequest() { public boolean isTriggerOnClosedPullRequest() {
return triggerOnClosedPullRequest; return triggerOnClosedPullRequest;
} }
@ -243,6 +267,10 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
return ciSkip; return ciSkip;
} }
public BuildInstructionFilterType getBuildInstructionFilterType() {
return buildInstructionFilterType;
}
public boolean getCiSkipFroTestNotRequired() { public boolean getCiSkipFroTestNotRequired() {
return ciSkipFroTestNotRequired; return ciSkipFroTestNotRequired;
} }
@ -295,11 +323,15 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
return this.cancelPendingBuildsOnUpdate; return this.cancelPendingBuildsOnUpdate;
} }
public boolean isCancelIncompleteBuildOnSamePullRequest() {
return cancelIncompleteBuildOnSamePullRequest;
}
@DataBoundSetter @DataBoundSetter
public void setTriggerOnPush(boolean triggerOnPush) { public void setTriggerOnPush(boolean triggerOnPush) {
this.triggerOnPush = triggerOnPush; this.triggerOnPush = triggerOnPush;
} }
@DataBoundSetter @DataBoundSetter
public void setTriggerOnApprovedPullRequest(boolean triggerOnApprovedPullRequest) { public void setTriggerOnApprovedPullRequest(boolean triggerOnApprovedPullRequest) {
this.triggerOnApprovedPullRequest = triggerOnApprovedPullRequest; this.triggerOnApprovedPullRequest = triggerOnApprovedPullRequest;
@ -340,6 +372,11 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
this.ciSkip = ciSkip; this.ciSkip = ciSkip;
} }
@DataBoundSetter
public void setBuildInstructionFilterType(BuildInstructionFilterType buildInstructionFilterType) {
this.buildInstructionFilterType = buildInstructionFilterType;
}
@DataBoundSetter @DataBoundSetter
public void setCiSkipFroTestNotRequired(boolean ciSkipFroTestNotRequired) { public void setCiSkipFroTestNotRequired(boolean ciSkipFroTestNotRequired) {
this.ciSkipFroTestNotRequired = ciSkipFroTestNotRequired; this.ciSkipFroTestNotRequired = ciSkipFroTestNotRequired;
@ -437,6 +474,11 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
this.cancelPendingBuildsOnUpdate = cancelPendingBuildsOnUpdate; this.cancelPendingBuildsOnUpdate = cancelPendingBuildsOnUpdate;
} }
@DataBoundSetter
public void setCancelIncompleteBuildOnSamePullRequest(boolean cancelIncompleteBuildOnSamePullRequest) {
this.cancelIncompleteBuildOnSamePullRequest = cancelIncompleteBuildOnSamePullRequest;
}
// executes when the Trigger receives a push request // executes when the Trigger receives a push request
public void onPost(final PushHook hook) { public void onPost(final PushHook hook) {
if (branchFilter == null) { if (branchFilter == null) {
@ -448,7 +490,7 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
if (pushHookTriggerHandler == null) { if (pushHookTriggerHandler == null) {
initializeTriggerHandler(); initializeTriggerHandler();
} }
pushHookTriggerHandler.handle(job, hook, ciSkip, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter); pushHookTriggerHandler.handle(job, hook, buildInstructionFilterType, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter);
} }
// executes when the Trigger receives a pull request // executes when the Trigger receives a pull request
@ -462,7 +504,7 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
if (pullRequestHookTriggerHandler == null) { if (pullRequestHookTriggerHandler == null) {
initializeTriggerHandler(); initializeTriggerHandler();
} }
pullRequestHookTriggerHandler.handle(job, hook, ciSkip, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter); pullRequestHookTriggerHandler.handle(job, hook, buildInstructionFilterType, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter);
} }
// executes when the Trigger receives a note request // executes when the Trigger receives a note request
@ -476,7 +518,7 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
if (noteHookTriggerHandler == null) { if (noteHookTriggerHandler == null) {
initializeTriggerHandler(); initializeTriggerHandler();
} }
noteHookTriggerHandler.handle(job, hook, ciSkip, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter); noteHookTriggerHandler.handle(job, hook, buildInstructionFilterType, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter);
} }
// executes when the Trigger receives a pipeline event // executes when the Trigger receives a pipeline event
@ -484,14 +526,16 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
if (pipelineTriggerHandler == null) { if (pipelineTriggerHandler == null) {
initializeTriggerHandler(); initializeTriggerHandler();
} }
pipelineTriggerHandler.handle(job, hook, ciSkip, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter); pipelineTriggerHandler.handle(job, hook, buildInstructionFilterType, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter);
} }
private void initializeTriggerHandler() { private void initializeTriggerHandler() {
pullRequestHookTriggerHandler = newPullRequestHookTriggerHandler(triggerOnOpenPullRequest, pullRequestHookTriggerHandler = newPullRequestHookTriggerHandler(triggerOnOpenPullRequest,
triggerOnUpdatePullRequest, triggerOnAcceptedPullRequest, triggerOnClosedPullRequest, triggerOnUpdatePullRequest, triggerOnAcceptedPullRequest, triggerOnClosedPullRequest,
skipWorkInProgressPullRequest, triggerOnApprovedPullRequest, triggerOnTestedPullRequest, cancelPendingBuildsOnUpdate, ciSkipFroTestNotRequired); skipWorkInProgressPullRequest, triggerOnApprovedPullRequest, triggerOnTestedPullRequest, cancelPendingBuildsOnUpdate, ciSkipFroTestNotRequired,
noteHookTriggerHandler = newNoteHookTriggerHandler(triggerOnNoteRequest, noteRegex, ciSkipFroTestNotRequired); cancelIncompleteBuildOnSamePullRequest
);
noteHookTriggerHandler = newNoteHookTriggerHandler(triggerOnNoteRequest, noteRegex, ciSkipFroTestNotRequired, cancelIncompleteBuildOnSamePullRequest);
pushHookTriggerHandler = newPushHookTriggerHandler(triggerOnPush, skipWorkInProgressPullRequest); pushHookTriggerHandler = newPushHookTriggerHandler(triggerOnPush, skipWorkInProgressPullRequest);
pipelineTriggerHandler = newPipelineHookTriggerHandler(triggerOnPipelineEvent); pipelineTriggerHandler = newPipelineHookTriggerHandler(triggerOnPipelineEvent);
} }
@ -540,6 +584,7 @@ public class GiteePushTrigger extends Trigger<Job<?, ?>> {
private transient final SequentialExecutionQueue queue = new SequentialExecutionQueue(Jenkins.MasterComputer.threadPoolForRemoting); private transient final SequentialExecutionQueue queue = new SequentialExecutionQueue(Jenkins.MasterComputer.threadPoolForRemoting);
private boolean jobsMigrated = false; private boolean jobsMigrated = false;
private boolean jobsMigrated2 = false; private boolean jobsMigrated2 = false;
private boolean jobsMigrated3 = false;
private String GiteeApiToken; private String GiteeApiToken;
private String giteeHostUrl = ""; private String giteeHostUrl = "";
private boolean ignoreCertificateErrors = false; private boolean ignoreCertificateErrors = false;

View File

@ -0,0 +1,16 @@
package com.gitee.jenkins.trigger.filter;
/**
* @author zhanggx
*/
public interface BuildInstructionFilter {
/**
* 是否触发构建
*
* @param body
* @return
*/
boolean isBuildAllow(String body);
}

View File

@ -0,0 +1,46 @@
package com.gitee.jenkins.trigger.filter;
/**
* @author zhanggx
*/
public enum BuildInstructionFilterType implements BuildInstructionFilter {
/**
* 无操作
*/
NONE("") {
@Override
public boolean isBuildAllow(String body) {
return true;
}
},
/**
* 包含 [ci-skip] 时跳过构建
*/
CI_SKIP("[ci-skip]") {
@Override
public boolean isBuildAllow(String body) {
return body == null ? true : !body.contains(getBody());
}
},
/**
* 包含 [ci-build] 时触发构建
*/
CI_BUILD("[ci-build]") {
@Override
public boolean isBuildAllow(String body) {
return body == null ? false : body.contains(getBody());
}
};
private String body;
BuildInstructionFilterType(String body) {
this.body = body;
}
public String getBody() {
return body;
}
}

View File

@ -5,6 +5,7 @@ import com.gitee.jenkins.cause.GiteeWebHookCause;
import com.gitee.jenkins.gitee.hook.model.WebHook; import com.gitee.jenkins.gitee.hook.model.WebHook;
import com.gitee.jenkins.trigger.exception.NoRevisionToBuildException; import com.gitee.jenkins.trigger.exception.NoRevisionToBuildException;
import com.gitee.jenkins.trigger.filter.BranchFilter; import com.gitee.jenkins.trigger.filter.BranchFilter;
import com.gitee.jenkins.trigger.filter.BuildInstructionFilter;
import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter; import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter;
import com.gitee.jenkins.util.LoggerUtil; import com.gitee.jenkins.util.LoggerUtil;
import hudson.model.Action; import hudson.model.Action;
@ -34,8 +35,8 @@ public abstract class AbstractWebHookTriggerHandler<H extends WebHook> implement
protected PendingBuildsHandler pendingBuildsHandler = new PendingBuildsHandler(); protected PendingBuildsHandler pendingBuildsHandler = new PendingBuildsHandler();
@Override @Override
public void handle(Job<?, ?> job, H hook, boolean ciSkip, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) { public void handle(Job<?, ?> job, H hook, BuildInstructionFilter buildInstructionFilter, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) {
if (ciSkip && isCiSkip(hook)) { if (isCiSkip(hook, buildInstructionFilter)) {
LOGGER.log(Level.INFO, "Skipping due to ci-skip."); LOGGER.log(Level.INFO, "Skipping due to ci-skip.");
return; return;
} }
@ -49,6 +50,7 @@ public abstract class AbstractWebHookTriggerHandler<H extends WebHook> implement
if (branchFilter.isBranchAllowed(targetBranch)) { if (branchFilter.isBranchAllowed(targetBranch)) {
LOGGER.log(Level.INFO, "{0} triggered for {1}.", LoggerUtil.toArray(job.getFullName(), getTriggerType())); LOGGER.log(Level.INFO, "{0} triggered for {1}.", LoggerUtil.toArray(job.getFullName(), getTriggerType()));
cancelPendingBuildsIfNecessary(job, hook); cancelPendingBuildsIfNecessary(job, hook);
cancelIncompleteBuildIfNecessary(job, hook);
scheduleBuild(job, createActions(job, hook)); scheduleBuild(job, createActions(job, hook));
} else { } else {
LOGGER.log(Level.INFO, "branch {0} is not allowed", targetBranch); LOGGER.log(Level.INFO, "branch {0} is not allowed", targetBranch);
@ -57,7 +59,7 @@ public abstract class AbstractWebHookTriggerHandler<H extends WebHook> implement
protected abstract String getTriggerType(); protected abstract String getTriggerType();
protected abstract boolean isCiSkip(H hook); protected abstract boolean isCiSkip(H hook, BuildInstructionFilter buildInstructionFilter);
protected abstract boolean isCommitSkip(Job<?, ?> job, H hook); protected abstract boolean isCommitSkip(Job<?, ?> job, H hook);
protected Action[] createActions(Job<?, ?> job, H hook) { protected Action[] createActions(Job<?, ?> job, H hook) {
@ -76,6 +78,8 @@ public abstract class AbstractWebHookTriggerHandler<H extends WebHook> implement
protected void cancelPendingBuildsIfNecessary(Job<?, ?> job, H hook) {} protected void cancelPendingBuildsIfNecessary(Job<?, ?> job, H hook) {}
protected void cancelIncompleteBuildIfNecessary(Job<?, ?> job, H hook) {}
protected abstract CauseData retrieveCauseData(H hook); protected abstract CauseData retrieveCauseData(H hook);
protected abstract String getTargetBranch(H hook); protected abstract String getTargetBranch(H hook);

View File

@ -2,6 +2,7 @@ package com.gitee.jenkins.trigger.handler;
import com.gitee.jenkins.gitee.hook.model.WebHook; import com.gitee.jenkins.gitee.hook.model.WebHook;
import com.gitee.jenkins.trigger.filter.BranchFilter; import com.gitee.jenkins.trigger.filter.BranchFilter;
import com.gitee.jenkins.trigger.filter.BuildInstructionFilter;
import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter; import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter;
import hudson.model.Job; import hudson.model.Job;
@ -10,5 +11,6 @@ import hudson.model.Job;
*/ */
public interface WebHookTriggerHandler<H extends WebHook> { public interface WebHookTriggerHandler<H extends WebHook> {
void handle(Job<?, ?> job, H hook, boolean ciSkip, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter); void handle(Job<?, ?> job, H hook, BuildInstructionFilter buildInstructionFilter, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter);
} }

View File

@ -2,6 +2,7 @@ package com.gitee.jenkins.trigger.handler.note;
import com.gitee.jenkins.gitee.hook.model.NoteHook; import com.gitee.jenkins.gitee.hook.model.NoteHook;
import com.gitee.jenkins.trigger.filter.BranchFilter; import com.gitee.jenkins.trigger.filter.BranchFilter;
import com.gitee.jenkins.trigger.filter.BuildInstructionFilter;
import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter; import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter;
import hudson.model.Job; import hudson.model.Job;
@ -10,7 +11,7 @@ import hudson.model.Job;
*/ */
class NopNoteHookTriggerHandler implements NoteHookTriggerHandler { class NopNoteHookTriggerHandler implements NoteHookTriggerHandler {
@Override @Override
public void handle(Job<?, ?> job, NoteHook hook, boolean ciSkip, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) { public void handle(Job<?, ?> job, NoteHook hook, BuildInstructionFilter buildInstructionFilter, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) {
// nothing to do // nothing to do
} }
} }

View File

@ -7,9 +7,9 @@ public final class NoteHookTriggerHandlerFactory {
private NoteHookTriggerHandlerFactory() {} private NoteHookTriggerHandlerFactory() {}
public static NoteHookTriggerHandler newNoteHookTriggerHandler(boolean triggerOnNoteRequest, String noteRegex, boolean ciSkipFroTestNotRequired) { public static NoteHookTriggerHandler newNoteHookTriggerHandler(boolean triggerOnNoteRequest, String noteRegex, boolean ciSkipFroTestNotRequired, boolean cancelIncompleteBuildOnSamePullRequest) {
if (triggerOnNoteRequest) { if (triggerOnNoteRequest) {
return new NoteHookTriggerHandlerImpl(noteRegex, ciSkipFroTestNotRequired); return new NoteHookTriggerHandlerImpl(noteRegex, ciSkipFroTestNotRequired, cancelIncompleteBuildOnSamePullRequest);
} else { } else {
return new NopNoteHookTriggerHandler(); return new NopNoteHookTriggerHandler();
} }

View File

@ -7,12 +7,21 @@ import com.gitee.jenkins.gitee.hook.model.*;
import com.gitee.jenkins.publisher.GiteeMessagePublisher; import com.gitee.jenkins.publisher.GiteeMessagePublisher;
import com.gitee.jenkins.trigger.exception.NoRevisionToBuildException; import com.gitee.jenkins.trigger.exception.NoRevisionToBuildException;
import com.gitee.jenkins.trigger.filter.BranchFilter; import com.gitee.jenkins.trigger.filter.BranchFilter;
import com.gitee.jenkins.trigger.filter.BuildInstructionFilter;
import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter; import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter;
import com.gitee.jenkins.trigger.handler.AbstractWebHookTriggerHandler; import com.gitee.jenkins.trigger.handler.AbstractWebHookTriggerHandler;
import hudson.model.AbstractBuild;
import hudson.model.Job; import hudson.model.Job;
import hudson.model.Run;
import hudson.plugins.git.GitSCM; import hudson.plugins.git.GitSCM;
import hudson.plugins.git.RevisionParameterAction; import hudson.plugins.git.RevisionParameterAction;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.transport.RemoteConfig;
import javax.servlet.ServletException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -31,14 +40,16 @@ class NoteHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<NoteHook>
private final String noteRegex; private final String noteRegex;
private final boolean ciSkipFroTestNotRequired; private final boolean ciSkipFroTestNotRequired;
private final boolean cancelIncompleteBuildOnSamePullRequest;
NoteHookTriggerHandlerImpl(String noteRegex, boolean ciSkipFroTestNotRequired) { NoteHookTriggerHandlerImpl(String noteRegex, boolean ciSkipFroTestNotRequired, boolean cancelIncompleteBuildOnSamePullRequest) {
this.noteRegex = noteRegex; this.noteRegex = noteRegex;
this.ciSkipFroTestNotRequired = ciSkipFroTestNotRequired; this.ciSkipFroTestNotRequired = ciSkipFroTestNotRequired;
this.cancelIncompleteBuildOnSamePullRequest = cancelIncompleteBuildOnSamePullRequest;
} }
@Override @Override
public void handle(Job<?, ?> job, NoteHook hook, boolean ciSkip, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) { public void handle(Job<?, ?> job, NoteHook hook, BuildInstructionFilter buildInstructionFilter, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) {
if (isValidTrigger(hook)) { if (isValidTrigger(hook)) {
// 若pr不可自动合并则评论至pr // 若pr不可自动合并则评论至pr
PullRequestObjectAttributes objectAttributes = hook.getPullRequest(); PullRequestObjectAttributes objectAttributes = hook.getPullRequest();
@ -61,21 +72,56 @@ class NoteHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<NoteHook>
} }
super.handle(job, hook, ciSkip, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter); super.handle(job, hook, buildInstructionFilter, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter);
} }
} }
@Override @Override
protected boolean isCiSkip(NoteHook hook) { protected boolean isCiSkip(NoteHook hook, BuildInstructionFilter buildInstructionFilter) {
return hook.getPullRequest() != null return hook.getPullRequest() == null ? false : !buildInstructionFilter.isBuildAllow(hook.getPullRequest().getBody());
&& hook.getPullRequest().getBody() != null
&& hook.getPullRequest().getBody().contains("[ci-skip]");
} }
@Override @Override
protected boolean isCommitSkip(Job<?, ?> project, NoteHook hook) { protected boolean isCommitSkip(Job<?, ?> project, NoteHook hook) {
return false; return false;
} }
@Override
protected void cancelIncompleteBuildIfNecessary(Job<?, ?> job, NoteHook hook) {
if (!cancelIncompleteBuildOnSamePullRequest || hook.getPullRequest() == null) {
return;
}
for (Run<?, ?> build : job.getBuilds()) {
if (!job.isBuilding()) {
break;
}
if (!build.isBuilding()) {
continue;
}
RevisionParameterAction revisionParameterAction = build.getAction(RevisionParameterAction.class);
if (revisionParameterAction != null) {
Config config = new Config();
config.setString("remote", hook.getRepository().getName(), "url", hook.getRepository().getGitHttpUrl());
try {
if (revisionParameterAction.canOriginateFrom(RemoteConfig.getAllRemoteConfigs(config))
&& revisionParameterAction.commit.equals(hook.getPullRequest().getMergeReferenceName())) {
if (build.isBuilding()) {
((AbstractBuild) build).doStop();
LOGGER.log(Level.WARNING, "Abort incomplete build");
}
}
} catch (URISyntaxException e) {
LOGGER.log(Level.WARNING, "Parsing repo url error", e);
} catch (ServletException | IOException e) {
LOGGER.log(Level.WARNING, "Unable to abort incomplete build", e);
}
}
}
}
@Override @Override
protected String getTargetBranch(NoteHook hook) { protected String getTargetBranch(NoteHook hook) {
return hook.getPullRequest() == null ? null : hook.getPullRequest().getTargetBranch(); return hook.getPullRequest() == null ? null : hook.getPullRequest().getTargetBranch();
@ -88,6 +134,35 @@ class NoteHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<NoteHook>
@Override @Override
protected CauseData retrieveCauseData(NoteHook hook) { protected CauseData retrieveCauseData(NoteHook hook) {
// 兼容来自commit的评论
if (hook.getPullRequest() == null) {
return causeData()
.withActionType(CauseData.ActionType.COMMIT_COMMENT)
.withUserName(hook.getComment().getUser().getUsername())
.withUserEmail(hook.getComment().getUser().getEmail())
.withPullRequestTitle("")
.withBranch("")
.withSourceBranch("")
.withSourceProjectId(hook.getProject().getId())
.withSourceRepoHomepage(hook.getProject().getHomepage())
.withSourceRepoName(hook.getProject().getName())
.withSourceNamespace(hook.getProject().getNamespace())
.withSourceRepoUrl(hook.getProject().getUrl())
.withSourceRepoSshUrl(hook.getProject().getSshUrl())
.withSourceRepoHttpUrl(hook.getProject().getGitHttpUrl())
.withTargetBranch("")
.withTargetProjectId(hook.getProject().getId())
.withTargetRepoName(hook.getProject().getName())
.withTargetNamespace(hook.getProject().getNamespace())
.withTargetRepoSshUrl(hook.getProject().getSshUrl())
.withTargetRepoHttpUrl(hook.getProject().getGitHttpUrl())
.withTriggeredByUser(hook.getComment().getUser().getName())
.withTriggerPhrase(hook.getComment().getBody())
.withSha(hook.getComment().getCommitId())
.withPathWithNamespace(hook.getProject().getPathWithNamespace())
.build();
}
return causeData() return causeData()
.withActionType(CauseData.ActionType.NOTE) .withActionType(CauseData.ActionType.NOTE)
.withSourceProjectId(hook.getPullRequest().getSourceProjectId()) .withSourceProjectId(hook.getPullRequest().getSourceProjectId())
@ -146,6 +221,13 @@ class NoteHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<NoteHook>
return hook.getPullRequest().getMergeReferenceName(); return hook.getPullRequest().getMergeReferenceName();
} }
} }
// 兼容来自commit的评论
if (hook.getComment() != null
&& StringUtils.isNotBlank(hook.getComment().getCommitId())) {
return hook.getComment().getCommitId();
}
throw new NoRevisionToBuildException(); throw new NoRevisionToBuildException();
} }

View File

@ -2,6 +2,7 @@ package com.gitee.jenkins.trigger.handler.pipeline;
import com.gitee.jenkins.gitee.hook.model.PipelineHook; import com.gitee.jenkins.gitee.hook.model.PipelineHook;
import com.gitee.jenkins.trigger.filter.BranchFilter; import com.gitee.jenkins.trigger.filter.BranchFilter;
import com.gitee.jenkins.trigger.filter.BuildInstructionFilter;
import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter; import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter;
import hudson.model.Job; import hudson.model.Job;
@ -11,7 +12,7 @@ import hudson.model.Job;
class NopPipelineHookTriggerHandler implements PipelineHookTriggerHandler { class NopPipelineHookTriggerHandler implements PipelineHookTriggerHandler {
@Override @Override
public void handle(Job<?, ?> job, PipelineHook hook, boolean ciSkip, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) { public void handle(Job<?, ?> job, PipelineHook hook, BuildInstructionFilter buildInstructionFilter, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) {
} }
} }

View File

@ -8,6 +8,7 @@ import com.gitee.jenkins.gitee.hook.model.PipelineEventObjectAttributes;
import com.gitee.jenkins.gitee.hook.model.PipelineHook; import com.gitee.jenkins.gitee.hook.model.PipelineHook;
import com.gitee.jenkins.trigger.exception.NoRevisionToBuildException; import com.gitee.jenkins.trigger.exception.NoRevisionToBuildException;
import com.gitee.jenkins.trigger.filter.BranchFilter; import com.gitee.jenkins.trigger.filter.BranchFilter;
import com.gitee.jenkins.trigger.filter.BuildInstructionFilter;
import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter; import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter;
import com.gitee.jenkins.trigger.handler.AbstractWebHookTriggerHandler; import com.gitee.jenkins.trigger.handler.AbstractWebHookTriggerHandler;
import com.gitee.jenkins.util.BuildUtil; import com.gitee.jenkins.util.BuildUtil;
@ -44,7 +45,7 @@ class PipelineHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<Pipel
} }
@Override @Override
public void handle(Job<?, ?> job, PipelineHook hook, boolean ciSkip, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) { public void handle(Job<?, ?> job, PipelineHook hook, BuildInstructionFilter buildInstructionFilter, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) {
PipelineEventObjectAttributes objectAttributes = hook.getObjectAttributes(); PipelineEventObjectAttributes objectAttributes = hook.getObjectAttributes();
try { try {
if (job instanceof AbstractProject<?, ?>) { if (job instanceof AbstractProject<?, ?>) {
@ -58,7 +59,7 @@ class PipelineHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<Pipel
LOGGER.log(Level.WARNING, "Failed to communicate with gitee server to determine project id: " + e.getMessage(), e); LOGGER.log(Level.WARNING, "Failed to communicate with gitee server to determine project id: " + e.getMessage(), e);
} }
if (allowedStates.contains(objectAttributes.getStatus()) && !isLastAlreadyBuild(job,hook)) { if (allowedStates.contains(objectAttributes.getStatus()) && !isLastAlreadyBuild(job,hook)) {
if (ciSkip && isCiSkip(hook)) { if (isCiSkip(hook, buildInstructionFilter)) {
LOGGER.log(Level.INFO, "Skipping due to ci-skip."); LOGGER.log(Level.INFO, "Skipping due to ci-skip.");
return; return;
} }
@ -77,7 +78,7 @@ class PipelineHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<Pipel
} }
@Override @Override
protected boolean isCiSkip(PipelineHook hook) { protected boolean isCiSkip(PipelineHook hook, BuildInstructionFilter buildInstructionFilter) {
//we don't get a commit message or suchlike that could contain ci-skip //we don't get a commit message or suchlike that could contain ci-skip
return false; return false;
} }

View File

@ -2,6 +2,7 @@ package com.gitee.jenkins.trigger.handler.pull;
import com.gitee.jenkins.gitee.hook.model.PullRequestHook; import com.gitee.jenkins.gitee.hook.model.PullRequestHook;
import com.gitee.jenkins.trigger.filter.BranchFilter; import com.gitee.jenkins.trigger.filter.BranchFilter;
import com.gitee.jenkins.trigger.filter.BuildInstructionFilter;
import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter; import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter;
import hudson.model.Job; import hudson.model.Job;
@ -10,7 +11,7 @@ import hudson.model.Job;
*/ */
class NopPullRequestHookTriggerHandler implements PullRequestHookTriggerHandler { class NopPullRequestHookTriggerHandler implements PullRequestHookTriggerHandler {
@Override @Override
public void handle(Job<?, ?> job, PullRequestHook hook, boolean ciSkip, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) { public void handle(Job<?, ?> job, PullRequestHook hook, BuildInstructionFilter buildInstructionFilter, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) {
// nothing to do // nothing to do
} }
} }

View File

@ -15,14 +15,15 @@ public final class PullRequestHookTriggerHandlerFactory {
private PullRequestHookTriggerHandlerFactory() {} private PullRequestHookTriggerHandlerFactory() {}
public static PullRequestHookTriggerHandler newPullRequestHookTriggerHandler(boolean triggerOnOpenPullRequest, public static PullRequestHookTriggerHandler newPullRequestHookTriggerHandler(boolean triggerOnOpenPullRequest,
String triggerOnUpdatePullRequest, String triggerOnUpdatePullRequest,
boolean triggerOnAcceptedPullRequest, boolean triggerOnAcceptedPullRequest,
boolean triggerOnClosedPullRequest, boolean triggerOnClosedPullRequest,
boolean skipWorkInProgressPullRequest, boolean skipWorkInProgressPullRequest,
boolean triggerOnApprovedPullRequest, boolean triggerOnApprovedPullRequest,
boolean triggerOnTestedPullRequest, boolean triggerOnTestedPullRequest,
boolean cancelPendingBuildsOnUpdate, boolean cancelPendingBuildsOnUpdate,
boolean ciSkipFroTestNotRequired) { boolean ciSkipFroTestNotRequired,
boolean cancelIncompleteBuildOnSamePullRequest) {
if (triggerOnOpenPullRequest if (triggerOnOpenPullRequest
|| !("0".equals(triggerOnUpdatePullRequest) || "false".equals(triggerOnUpdatePullRequest)) || !("0".equals(triggerOnUpdatePullRequest) || "false".equals(triggerOnUpdatePullRequest))
|| triggerOnAcceptedPullRequest || triggerOnAcceptedPullRequest
@ -46,7 +47,8 @@ public final class PullRequestHookTriggerHandlerFactory {
retrieveAllowedActionDesces(triggerOnUpdatePullRequest), retrieveAllowedActionDesces(triggerOnUpdatePullRequest),
skipWorkInProgressPullRequest, skipWorkInProgressPullRequest,
cancelPendingBuildsOnUpdate, cancelPendingBuildsOnUpdate,
ciSkipFroTestNotRequired); ciSkipFroTestNotRequired,
cancelIncompleteBuildOnSamePullRequest);
} else { } else {
return new NopPullRequestHookTriggerHandler(); return new NopPullRequestHookTriggerHandler();
} }
@ -135,7 +137,7 @@ public final class PullRequestHookTriggerHandlerFactory {
if (triggerOnClosedPullRequest) { if (triggerOnClosedPullRequest) {
result.add(State.closed); result.add(State.closed);
} }
return result; return result;
} }
} }

View File

@ -9,15 +9,22 @@ import com.gitee.jenkins.gitee.hook.model.PullRequestHook;
import com.gitee.jenkins.publisher.GiteeMessagePublisher; import com.gitee.jenkins.publisher.GiteeMessagePublisher;
import com.gitee.jenkins.trigger.exception.NoRevisionToBuildException; import com.gitee.jenkins.trigger.exception.NoRevisionToBuildException;
import com.gitee.jenkins.trigger.filter.BranchFilter; import com.gitee.jenkins.trigger.filter.BranchFilter;
import com.gitee.jenkins.trigger.filter.BuildInstructionFilter;
import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter; import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter;
import com.gitee.jenkins.trigger.handler.AbstractWebHookTriggerHandler; import com.gitee.jenkins.trigger.handler.AbstractWebHookTriggerHandler;
import com.gitee.jenkins.util.BuildUtil; import com.gitee.jenkins.util.BuildUtil;
import hudson.model.AbstractBuild;
import hudson.model.Job; import hudson.model.Job;
import hudson.model.Run; import hudson.model.Run;
import hudson.plugins.git.GitSCM; import hudson.plugins.git.GitSCM;
import hudson.plugins.git.RevisionParameterAction; import hudson.plugins.git.RevisionParameterAction;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.transport.RemoteConfig;
import javax.servlet.ServletException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collection; import java.util.Collection;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -43,22 +50,24 @@ class PullRequestHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<Pu
private final Collection<Action> allowedActions; private final Collection<Action> allowedActions;
private final Collection<ActionDesc> allowedActionDesces; private final Collection<ActionDesc> allowedActionDesces;
private final boolean cancelPendingBuildsOnUpdate; private final boolean cancelPendingBuildsOnUpdate;
private final boolean cancelIncompleteBuildOnSamePullRequest;
PullRequestHookTriggerHandlerImpl(Collection<State> allowedStates, boolean skipWorkInProgressPullRequest, boolean cancelPendingBuildsOnUpdate, boolean ciSkipFroTestNotRequired) { PullRequestHookTriggerHandlerImpl(Collection<State> allowedStates, boolean skipWorkInProgressPullRequest, boolean cancelPendingBuildsOnUpdate, boolean ciSkipFroTestNotRequired, boolean cancelIncompleteBuildOnSamePullRequest) {
this(allowedStates, EnumSet.allOf(Action.class), EnumSet.allOf(ActionDesc.class), skipWorkInProgressPullRequest, cancelPendingBuildsOnUpdate, ciSkipFroTestNotRequired); this(allowedStates, EnumSet.allOf(Action.class), EnumSet.allOf(ActionDesc.class), skipWorkInProgressPullRequest, cancelPendingBuildsOnUpdate, ciSkipFroTestNotRequired, cancelIncompleteBuildOnSamePullRequest);
} }
PullRequestHookTriggerHandlerImpl(Collection<State> allowedStates, Collection<Action> allowedActions, Collection<ActionDesc> allowedActionDesces, boolean skipWorkInProgressPullRequest, boolean cancelPendingBuildsOnUpdate, boolean ciSkipFroTestNotRequired) { PullRequestHookTriggerHandlerImpl(Collection<State> allowedStates, Collection<Action> allowedActions, Collection<ActionDesc> allowedActionDesces, boolean skipWorkInProgressPullRequest, boolean cancelPendingBuildsOnUpdate, boolean ciSkipFroTestNotRequired, boolean cancelIncompleteBuildOnSamePullRequest) {
this.allowedStates = allowedStates; this.allowedStates = allowedStates;
this.allowedActions = allowedActions; this.allowedActions = allowedActions;
this.allowedActionDesces = allowedActionDesces; this.allowedActionDesces = allowedActionDesces;
this.skipWorkInProgressPullRequest = skipWorkInProgressPullRequest; this.skipWorkInProgressPullRequest = skipWorkInProgressPullRequest;
this.cancelPendingBuildsOnUpdate = cancelPendingBuildsOnUpdate; this.cancelPendingBuildsOnUpdate = cancelPendingBuildsOnUpdate;
this.ciSkipFroTestNotRequired = ciSkipFroTestNotRequired; this.ciSkipFroTestNotRequired = ciSkipFroTestNotRequired;
this.cancelIncompleteBuildOnSamePullRequest = cancelIncompleteBuildOnSamePullRequest;
} }
@Override @Override
public void handle(Job<?, ?> job, PullRequestHook hook, boolean ciSkip, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) { public void handle(Job<?, ?> job, PullRequestHook hook, BuildInstructionFilter buildInstructionFilter, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) {
PullRequestObjectAttributes objectAttributes = hook.getPullRequest(); PullRequestObjectAttributes objectAttributes = hook.getPullRequest();
try { try {
@ -93,7 +102,7 @@ class PullRequestHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<Pu
} }
if (pullRequestLabelFilter.isPullRequestAllowed(labelsNames)) { if (pullRequestLabelFilter.isPullRequestAllowed(labelsNames)) {
super.handle(job, hook, ciSkip, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter); super.handle(job, hook, buildInstructionFilter, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter);
} }
} }
else { else {
@ -107,10 +116,8 @@ class PullRequestHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<Pu
} }
@Override @Override
protected boolean isCiSkip(PullRequestHook hook) { protected boolean isCiSkip(PullRequestHook hook, BuildInstructionFilter buildInstructionFilter) {
return hook.getPullRequest() != null return hook.getPullRequest() == null ? false : !buildInstructionFilter.isBuildAllow(hook.getPullRequest().getBody());
&& hook.getPullRequest().getBody() != null
&& hook.getPullRequest().getBody().contains("[ci-skip]");
} }
@Override @Override
@ -138,6 +145,43 @@ class PullRequestHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<Pu
this.pendingBuildsHandler.cancelPendingBuilds(job, hook.getPullRequest().getSourceProjectId(), hook.getPullRequest().getSourceBranch()); this.pendingBuildsHandler.cancelPendingBuilds(job, hook.getPullRequest().getSourceProjectId(), hook.getPullRequest().getSourceBranch());
} }
@Override
protected void cancelIncompleteBuildIfNecessary(Job<?, ?> job, PullRequestHook hook) {
if (!cancelIncompleteBuildOnSamePullRequest) {
return;
}
for (Run<?, ?> build : job.getBuilds()) {
if (!job.isBuilding()) {
break;
}
if (!build.isBuilding()) {
continue;
}
RevisionParameterAction revisionParameterAction = build.getAction(RevisionParameterAction.class);
if (revisionParameterAction != null) {
Config config = new Config();
config.setString("remote", hook.getRepo().getName(), "url", hook.getRepo().getGitHttpUrl());
try {
if (revisionParameterAction.canOriginateFrom(RemoteConfig.getAllRemoteConfigs(config))
&& revisionParameterAction.commit.equals(hook.getPullRequest().getMergeReferenceName())) {
if (build.isBuilding()) {
((AbstractBuild) build).doStop();
LOGGER.log(Level.WARNING, "Abort incomplete build");
}
}
} catch (URISyntaxException e) {
LOGGER.log(Level.WARNING, "Parsing repo url error", e);
} catch (ServletException | IOException e) {
LOGGER.log(Level.WARNING, "Unable to abort incomplete build", e);
}
}
}
}
@Override @Override
protected String getTargetBranch(PullRequestHook hook) { protected String getTargetBranch(PullRequestHook hook) {
return hook.getPullRequest() == null ? null : hook.getPullRequest().getTargetBranch(); return hook.getPullRequest() == null ? null : hook.getPullRequest().getTargetBranch();

View File

@ -2,6 +2,7 @@ package com.gitee.jenkins.trigger.handler.push;
import com.gitee.jenkins.gitee.hook.model.PushHook; import com.gitee.jenkins.gitee.hook.model.PushHook;
import com.gitee.jenkins.trigger.filter.BranchFilter; import com.gitee.jenkins.trigger.filter.BranchFilter;
import com.gitee.jenkins.trigger.filter.BuildInstructionFilter;
import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter; import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter;
import hudson.model.Job; import hudson.model.Job;
@ -10,7 +11,7 @@ import hudson.model.Job;
*/ */
class NopPushHookTriggerHandler implements PushHookTriggerHandler { class NopPushHookTriggerHandler implements PushHookTriggerHandler {
@Override @Override
public void handle(Job<?, ?> job, PushHook hook, boolean ciSkip, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) { public void handle(Job<?, ?> job, PushHook hook, BuildInstructionFilter buildInstructionFilter, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) {
// nothing to do // nothing to do
} }
} }

View File

@ -6,6 +6,7 @@ import com.gitee.jenkins.gitee.hook.model.Commit;
import com.gitee.jenkins.gitee.hook.model.PushHook; import com.gitee.jenkins.gitee.hook.model.PushHook;
import com.gitee.jenkins.trigger.exception.NoRevisionToBuildException; import com.gitee.jenkins.trigger.exception.NoRevisionToBuildException;
import com.gitee.jenkins.trigger.filter.BranchFilter; import com.gitee.jenkins.trigger.filter.BranchFilter;
import com.gitee.jenkins.trigger.filter.BuildInstructionFilter;
import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter; import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter;
import com.gitee.jenkins.trigger.handler.AbstractWebHookTriggerHandler; import com.gitee.jenkins.trigger.handler.AbstractWebHookTriggerHandler;
import hudson.model.Job; import hudson.model.Job;
@ -31,19 +32,19 @@ class PushHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<PushHook>
private static final String NO_COMMIT = "0000000000000000000000000000000000000000"; private static final String NO_COMMIT = "0000000000000000000000000000000000000000";
@Override @Override
public void handle(Job<?, ?> job, PushHook hook, boolean ciSkip, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) { public void handle(Job<?, ?> job, PushHook hook, BuildInstructionFilter buildInstructionFilter, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) {
if (isNoRemoveBranchPush(hook)) { if (isNoRemoveBranchPush(hook)) {
super.handle(job, hook, ciSkip, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter); super.handle(job, hook, buildInstructionFilter, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter);
} }
} }
@Override @Override
protected boolean isCiSkip(PushHook hook) { protected boolean isCiSkip(PushHook hook, BuildInstructionFilter buildInstructionFilter) {
List<Commit> commits = hook.getCommits(); List<Commit> commits = hook.getCommits();
return commits != null && if (commits != null && !commits.isEmpty()) {
!commits.isEmpty() && return !buildInstructionFilter.isBuildAllow(commits.get(commits.size() - 1).getMessage());
commits.get(commits.size() - 1).getMessage() != null && }
commits.get(commits.size() - 1).getMessage().contains("[ci-skip]"); return false;
} }
@Override @Override

View File

@ -2,6 +2,7 @@ package com.gitee.jenkins.trigger.handler.push;
import com.gitee.jenkins.gitee.hook.model.PushHook; import com.gitee.jenkins.gitee.hook.model.PushHook;
import com.gitee.jenkins.trigger.filter.BranchFilter; import com.gitee.jenkins.trigger.filter.BranchFilter;
import com.gitee.jenkins.trigger.filter.BuildInstructionFilter;
import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter; import com.gitee.jenkins.trigger.filter.PullRequestLabelFilter;
import hudson.model.Job; import hudson.model.Job;
@ -19,9 +20,9 @@ class PushHookTriggerHandlerList implements PushHookTriggerHandler {
} }
@Override @Override
public void handle(Job<?, ?> job, PushHook hook, boolean ciSkip, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) { public void handle(Job<?, ?> job, PushHook hook, BuildInstructionFilter buildInstructionFilter, boolean skipLastCommitHasBeenBuild, BranchFilter branchFilter, PullRequestLabelFilter pullRequestLabelFilter) {
for (PushHookTriggerHandler handler : handlers) { for (PushHookTriggerHandler handler : handlers) {
handler.handle(job, hook, ciSkip, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter); handler.handle(job, hook, buildInstructionFilter, skipLastCommitHasBeenBuild, branchFilter, pullRequestLabelFilter);
} }
} }
} }

View File

@ -4,5 +4,6 @@ GiteeWebHookCause.ShortDescription.PullRequestHook_html=Triggered by <a href="{3
GiteeWebHookCause.ShortDescription.PullRequestHook_plain=Triggered by Gitee Pull Request #{0}: {1} => {2} GiteeWebHookCause.ShortDescription.PullRequestHook_plain=Triggered by Gitee Pull Request #{0}: {1} => {2}
GiteeWebHookCause.ShortDescription.NoteHook_html=Triggered by {0} <a href="{4}/pulls/{1}" target="_blank">Gitee Pull Request #{1}</a>: {2} => {3} GiteeWebHookCause.ShortDescription.NoteHook_html=Triggered by {0} <a href="{4}/pulls/{1}" target="_blank">Gitee Pull Request #{1}</a>: {2} => {3}
GiteeWebHookCause.ShortDescription.NoteHook_plain=Triggered by {0} Gitee Pull Request #{1}: {2} => {3} GiteeWebHookCause.ShortDescription.NoteHook_plain=Triggered by {0} Gitee Pull Request #{1}: {2} => {3}
GiteeWebHookCause.ShortDescription.Commit_comment=Started by Gitee comment by {0}
GiteeWebHookCause.ShortDescription.PipelineHook_noStatus=Started by Gitee Pipeline event GiteeWebHookCause.ShortDescription.PipelineHook_noStatus=Started by Gitee Pipeline event
GiteeWebHookCause.ShortDescription.PipelineHook=Started by Gitee Pipeline event {0} GiteeWebHookCause.ShortDescription.PipelineHook=Started by Gitee Pipeline event {0}

View File

@ -4,5 +4,6 @@ GiteeWebHookCause.ShortDescription.PullRequestHook_html=\u7531 <a href="{3}/pull
GiteeWebHookCause.ShortDescription.PullRequestHook_plain=\u7531 Gitee Pull Request #{0}: {1} => {2} \u89E6\u53D1 GiteeWebHookCause.ShortDescription.PullRequestHook_plain=\u7531 Gitee Pull Request #{0}: {1} => {2} \u89E6\u53D1
GiteeWebHookCause.ShortDescription.NoteHook_html=\u7531 {0} <a href="{4}/pulls/{1}" target="_blank">Gitee Pull Request #{1}</a>: {2} => {3} \u89E6\u53D1 GiteeWebHookCause.ShortDescription.NoteHook_html=\u7531 {0} <a href="{4}/pulls/{1}" target="_blank">Gitee Pull Request #{1}</a>: {2} => {3} \u89E6\u53D1
GiteeWebHookCause.ShortDescription.NoteHook_plain=\u7531 {0} Gitee Pull Request #{1}: {2} => {3} \u89E6\u53D1 GiteeWebHookCause.ShortDescription.NoteHook_plain=\u7531 {0} Gitee Pull Request #{1}: {2} => {3} \u89E6\u53D1
GiteeWebHookCause.ShortDescription.Commit_comment=Gitee \u7528\u6237 {0} \u8BC4\u8BBA\u63D0\u4EA4\u89E6\u53D1\u6784\u5EFA
GiteeWebHookCause.ShortDescription.PipelineHook_noStatus=\u7531 Gitee Pipeline \u89E6\u53D1 GiteeWebHookCause.ShortDescription.PipelineHook_noStatus=\u7531 Gitee Pipeline \u89E6\u53D1
GiteeWebHookCause.ShortDescription.PipelineHook=\u7531 Gitee Pipeline {0} \u89E6\u53D1 GiteeWebHookCause.ShortDescription.PipelineHook=\u7531 Gitee Pipeline {0} \u89E6\u53D1

View File

@ -40,9 +40,29 @@
</f:entry> </f:entry>
</table> </table>
</f:entry> </f:entry>
<f:entry title="${%Enable.CI.Skip}" field="ciSkip" help="/plugin/gitee/help/help-ci-skip.html">
<f:checkbox default="true"/> <f:entry title="${%Build.Instruction.Filter}">
<table>
<f:radioBlock name="buildInstructionFilterType"
value="NONE"
title="${%Build.Instruction.Filter.None}"
checked="${instance.buildInstructionFilterType == null || instance.buildInstructionFilterType == 'NONE'}"
inline="true"/>
<f:radioBlock name="buildInstructionFilterType"
value="CI_SKIP"
title="${%Build.Instruction.Filter.CiSkip}"
checked="${instance.buildInstructionFilterType == 'CI_SKIP'}"
inline="true"
help="/plugin/gitee/help/help-ci-skip.html"/>
<f:radioBlock name="buildInstructionFilterType"
value="CI_BUILD"
title="${%Build.Instruction.Filter.CiBuild}"
checked="${instance.buildInstructionFilterType == 'CI_BUILD'}"
inline="true"
help="/plugin/gitee/help/help-ci-build.html"/>
</table>
</f:entry> </f:entry>
<f:entry title="${%Enable.CI.SkipFroTestNotRequired}" field="ciSkipFroTestNotRequired" help="/plugin/gitee/help/help-ci-skip-test.html"> <f:entry title="${%Enable.CI.SkipFroTestNotRequired}" field="ciSkipFroTestNotRequired" help="/plugin/gitee/help/help-ci-skip-test.html">
<f:checkbox default="true"/> <f:checkbox default="true"/>
</f:entry> </f:entry>
@ -50,6 +70,11 @@
<f:entry title="${%Ignore.Last.Commit.Has.Build}" field="skipLastCommitHasBeenBuild" help="/plugin/gitee/help/help-skip-last-commit.html"> <f:entry title="${%Ignore.Last.Commit.Has.Build}" field="skipLastCommitHasBeenBuild" help="/plugin/gitee/help/help-skip-last-commit.html">
<f:checkbox default="true"/> <f:checkbox default="true"/>
</f:entry> </f:entry>
<f:entry title="${%Cancel.Same.Pull.Request.Incomplete.Build}" field="cancelIncompleteBuildOnSamePullRequest" help="/plugin/gitee/help/help-cancel-same-pull-request-incomplete-build.html">
<f:checkbox default="false"/>
</f:entry>
<f:entry title="${%Allowed.branches}"> <f:entry title="${%Allowed.branches}">
<table> <table>
<!--<f:section title="">--> <!--<f:section title="">-->

View File

@ -3,6 +3,10 @@ Generate=Generate
Clear=Clear Clear=Clear
Push=Push Events Push=Push Events
Enable.CI.Skip=Enable [ci-skip] Enable.CI.Skip=Enable [ci-skip]
Build.Instruction.Filter=Build instruction filter
Build.Instruction.Filter.None=None
Build.Instruction.Filter.CiSkip=[ci-skip] skip build
Build.Instruction.Filter.CiBuild=[ci-build] trigger build
Enable.CI.SkipFroTestNotRequired=Skip ci when test not required Enable.CI.SkipFroTestNotRequired=Skip ci when test not required
Enabled.Gitee.Triggers=Enabled Gitee triggers Enabled.Gitee.Triggers=Enabled Gitee triggers
Approved.Pull.Request=Approved Pull Requests Approved.Pull.Request=Approved Pull Requests
@ -33,6 +37,7 @@ Filter.merge.request.by.label=Filter pull request by label
Exclude=Exclude Exclude=Exclude
Include=Include Include=Include
Ignore.Last.Commit.Has.Build=Ignore last commit has been build Ignore.Last.Commit.Has.Build=Ignore last commit has been build
Cancel.Same.Pull.Request.Incomplete.Build=Cancel incomplete build on same Pull Requests
Comments=Comment Pull Requests Comments=Comment Pull Requests
Comment.Regex=Comment (regex) for triggering a build Comment.Regex=Comment (regex) for triggering a build
Retry.Text=Jenkins please retry a build Retry.Text=Jenkins please retry a build

View File

@ -4,6 +4,10 @@ Clear=\u6E05\u9664
Push=\u63A8\u9001\u4EE3\u7801 Push=\u63A8\u9001\u4EE3\u7801
Enable.CI.Skip=\u652F\u6301 [ci-skip] \u6307\u4EE4\u8FC7\u6EE4\u6784\u5EFA Enable.CI.Skip=\u652F\u6301 [ci-skip] \u6307\u4EE4\u8FC7\u6EE4\u6784\u5EFA
Enable.CI.SkipFroTestNotRequired=PR \u4E0D\u8981\u6C42\u5FC5\u987B\u6D4B\u8BD5\u65F6\u8FC7\u6EE4\u6784\u5EFA Enable.CI.SkipFroTestNotRequired=PR \u4E0D\u8981\u6C42\u5FC5\u987B\u6D4B\u8BD5\u65F6\u8FC7\u6EE4\u6784\u5EFA
Build.Instruction.Filter=\u6784\u5EFA\u6307\u4EE4\u8FC7\u6EE4
Build.Instruction.Filter.None=\u65E0
Build.Instruction.Filter.CiSkip=[ci-skip] \u6307\u4EE4\u8DF3\u8FC7\u6784\u5EFA
Build.Instruction.Filter.CiBuild=[ci-build] \u6307\u4EE4\u89E6\u53D1\u6784\u5EFA
Enabled.Gitee.Triggers=Gitee \u89E6\u53D1\u6784\u5EFA\u7B56\u7565 Enabled.Gitee.Triggers=Gitee \u89E6\u53D1\u6784\u5EFA\u7B56\u7565
Approved.Pull.Request=\u5BA1\u67E5\u901A\u8FC7 Pull Requests Approved.Pull.Request=\u5BA1\u67E5\u901A\u8FC7 Pull Requests
Tested.Pull.Request=\u6D4B\u8BD5\u901A\u8FC7 Pull Requests Tested.Pull.Request=\u6D4B\u8BD5\u901A\u8FC7 Pull Requests
@ -33,6 +37,7 @@ Filter.merge.request.by.label=\u6839\u636E\u6807\u7B7E\u8FC7\u6EE4PR
Exclude=\u6392\u9664 Exclude=\u6392\u9664
Include=\u5305\u62EC Include=\u5305\u62EC
Ignore.Last.Commit.Has.Build=\u8FC7\u6EE4\u5DF2\u7ECF\u6784\u5EFA\u7684 Commit \u7248\u672C Ignore.Last.Commit.Has.Build=\u8FC7\u6EE4\u5DF2\u7ECF\u6784\u5EFA\u7684 Commit \u7248\u672C
Cancel.Same.Pull.Request.Incomplete.Build=\u53D6\u6D88\u76F8\u540C Pull Requests \u672A\u5B8C\u6210\u6784\u5EFA
Comments=\u8BC4\u8BBA Pull Requests Comments=\u8BC4\u8BBA Pull Requests
Comment.Regex=\u8BC4\u8BBA\u5185\u5BB9\u7684\u6B63\u5219\u8868\u8FBE\u5F0F Comment.Regex=\u8BC4\u8BBA\u5185\u5BB9\u7684\u6B63\u5219\u8868\u8FBE\u5F0F
Retry.Text=Jenkins please retry a build Retry.Text=Jenkins please retry a build

View File

@ -0,0 +1,4 @@
<div>
If there is an building build for the same PR,
cancel the building build and trigger the current build
</div>

View File

@ -0,0 +1,3 @@
<div>
如果相同 PR 存在进行中的构建,则取消进行中构建,触发当前构建
</div>

View File

@ -0,0 +1,4 @@
<div>
For Push hook: build if the commit message contains <code>[ci-build]</code>.
For Pull Request hook: build if the pull request body contains <code>[ci-build]</code>.
</div>

View File

@ -0,0 +1,8 @@
<div>
<p>
代码推送触发: 若推送的最后一个提交的描述信息包含 <code>[ci-build]</code>,则触发构建。
</p>
<p>
PR 操作触发: 若 PR 的内容描述信息包含 <code>[ci-build]</code>,则触发构建。
</p>
</div>