Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Illya Mazyriak 2015-11-14 14:05:41 +02:00
commit 2c9e47398e
9 changed files with 177 additions and 51 deletions

View File

@ -3,9 +3,18 @@ gitlab-plugin
This plugin emulates Jenkins as a GitlabCI Web Service to be used with GitlabHQ.
[![Build Status](https://travis-ci.org/DABSquared/gitlab-plugin.svg?branch=master)](https://travis-ci.org/DABSquared/gitlab-plugin)
[![Gitter chat](https://badges.gitter.im/DABSquared/gitlab-plugin.png)](https://gitter.im/DABSquared/gitlab-plugin)
Help Needed
=====================
* We are seeking help to maintain and improve this plugin. This includes keeping up a Changelog, releasing builds, reviewing merge requests, etc. If you are interested, please post to the Jenkins Developers list (https://groups.google.com/forum/#!forum/jenkinsci-dev) or ping autojack (@omehegan on Github) in #jenkins on irc.freenode.org IRC and ask for commit access.
Supported GitLab versions
======
* 7.14.x
Unsupported GitLab versions
======
* 8.0.x - in this version, GitLab folded the GitLabCI functionality into core GitLab, and in doing so broke the ability for the plugin to give build status to GitLab. **Jenkins build status will never work with GitLab 8.0.x!**
* 8.1.x - in this version, GitLab created a new public API to interface with external CI services like Jenkins. This plugin will be updated to support the new API; that work is incomplete at this time. See https://github.com/jenkinsci/gitlab-plugin/pull/127 for status.
Current Supported GitLabCI Functions
=====================
@ -17,22 +26,17 @@ Current Supported GitLabCI Functions
* `/project/PROJECT_NAME?ref=BRANCH_NAME` redirects to build page of the last build for `BRANCH_NAME`
* `/project/PROJECT_NAME` triggers a build, type (Merge Request or Push) depending on payload
Help Needed
=====================
* I am currently looking for someone to help maintain this project. This includes keeping up a Changelog, releasing builds, accepting merge requests, etc. If you are interested let @bass_rock know and I can add you as a maintainer.
Configuring access to Gitlab
=======================================
Optionally, the plugin communicates with the Gitlab server in order to fetch additional information. At this moment, this information is limited to fetching the source project of a Merge Request, in order to support merging from forked repositories.
To enable this functionality, a user should be set up on Gitlab, which adequate permissions to access the repository. On the global configuration screen, supply the gitlab host url ``http://your.gitlab.server`` and the API token of the user of choice.
To enable this functionality, a user should be set up on Gitlab, with adequate permissions to access the repository. On the global configuration screen, supply the gitlab host url ``http://your.gitlab.server`` and the API token of the user of choice.
Using it With A Job
=====================
* Create a new job by going to *New Job*
* Set the _Project Name_ to whatever you like
* If you have the GitHub plugin installed, feel free to specify the ``GitHub Project`` url as the url for the Gitlab project.
* In the *Source Code Management* section:
* Click *Git*
* Enter your *Repository URL* (e.g.: ``git@your.gitlab.server:group/repo_name.git``)
@ -60,15 +64,16 @@ Using it With A Job
* In GitLab go to you primary repository's project *Settings*
* Click on *Web Hooks*
* Add a Web Hook for *Merge Request Events* and *Push Events* to ``http://JENKINS_URL/project/PROJECT_NAME`` <br/>
**Note:** Currently GitLab 8.0 does not have a commit status api. Once this is added we should be able to add the commit status to Gitlab.
If you plan to use forked repositories, you will need to enable the GitLab CI integration on **each fork**.
* Go to the Settings page in each developer's fork
* Click on *Services*
* Click on *Web Hooks*
* Add a Web Hook for *Merge Request Events* and *Push Events* to ``http://JENKINS_URL/project/PROJECT_NAME`` <br/>
**Note:** Currently GitLab 8.0 does not have a commit status api. Once this is added we should be able to add the commit status to Gitlab.
**Note:** You do not need to select any "Trigger Events" as the Web Hook for Merge Request Events will alert Jenkins.
## Gitlab Configuration (≥ 8.1)
GitLab 8.1 uses the same configuration as GitLab 8.0
* GitLab 8.1 has implemented a commit status api. To enable this check the ``Use GitLab CI features`` under the project settings.
### GitLab Configuration (< 8.0)
* In GitLab go to you primary repository's project *Settings*
@ -97,7 +102,7 @@ Branch filtering
Triggers from push events may be filtered based on the branch name, i.e. the build will only be allowed for selected branches. On the project configuration page, a list of all branches on the remote repository is displayed under ``Build when a change is pushed to GitLab.``. It is possible to select multiple branches by holding Ctrl and clicking.
This functionality requires accessing the Gitlab server (see [above](#configuring-access-to-gitlab)) and for the time being also a git repository url already saved in the project configuration. In other words, when creating a new project, the configuration needs to be saved *once* before being able to select the allowed branches. For existing projects, all branches are allowed to push by default.
This functionality requires accessing the Gitlab server (see [above](#configuring-access-to-gitlab)) and for the time being also a git repository url already saved in the project configuration. In other words, when creating a new project, the configuration needs to be saved *once* before being able to select the allowed branches. For Workflow jobs, the configuration must be saved *and* the job must be run once before the list is populated. For existing projects, all branches are allowed to push by default.
Build Tags
================

View File

@ -140,7 +140,7 @@
<dependency>
<groupId>org.gitlab</groupId>
<artifactId>java-gitlab-api</artifactId>
<version>1.1.9</version>
<version>1.1.11</version>
</dependency>
</dependencies>
</project>

View File

@ -5,6 +5,9 @@ import java.util.Date;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.gitlab.api.GitlabAPI;
import org.gitlab.api.models.GitlabCommitStatus;
import org.gitlab.api.models.GitlabMergeRequest;
import org.gitlab.api.models.GitlabProject;
import org.gitlab.api.models.GitlabUser;
@ -61,6 +64,18 @@ public class GitLabMergeRequest extends GitLabRequest {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
public GitlabCommitStatus createCommitStatus(GitlabAPI api, String status, String targetUrl) {
try {
if(objectAttributes.lastCommit!=null) {
return api.createCommitStatus(sourceProject, objectAttributes.getLastCommit().getId(), status, objectAttributes.getLastCommit().getId(), "Jenkins", targetUrl, null);
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static class ObjectAttributes {
private Integer id;

View File

@ -10,24 +10,35 @@ import java.io.IOException;
*/
public class GitLabPushCause extends SCMTrigger.SCMTriggerCause {
private final String pushedBy;
private final GitLabPushRequest pushRequest;
public GitLabPushCause(String pushedBy) {
this.pushedBy = pushedBy;
public GitLabPushCause(GitLabPushRequest pushRequest) {
this.pushRequest=pushRequest;
}
public GitLabPushCause(String pushedBy, File logFile) throws IOException {
public GitLabPushCause(GitLabPushRequest pushRequest, File logFile) throws IOException{
super(logFile);
this.pushedBy = pushedBy;
this.pushRequest=pushRequest;
}
public GitLabPushCause(String pushedBy, String pollingLog) {
public GitLabPushCause(GitLabPushRequest pushRequest, String pollingLog) {
super(pollingLog);
this.pushedBy = pushedBy;
this.pushRequest=pushRequest;
}
public GitLabPushRequest getPushRequest() {
return pushRequest;
}
@Override
public String getShortDescription() {
String pushedBy;
if (pushRequest.getCommits().size() > 0){
pushedBy = pushRequest.getCommits().get(0).getAuthor().getName();
} else {
pushedBy = pushRequest.getUser_name();
}
if (pushedBy == null) {
return "Started by GitLab push";
} else {

View File

@ -1,9 +1,13 @@
package com.dabsquared.gitlabjenkins;
import java.io.IOException;
import java.util.List;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.gitlab.api.GitlabAPI;
import org.gitlab.api.models.GitlabCommitStatus;
import org.gitlab.api.models.GitlabProject;
/**
* Represents for WebHook payload
@ -23,6 +27,25 @@ public class GitLabPushRequest extends GitLabRequest {
public GitLabPushRequest() {
}
private GitlabProject sourceProject = null;
public GitlabProject getSourceProject (GitLab api) throws IOException {
if (sourceProject == null) {
sourceProject = api.instance().getProject(project_id);
}
return sourceProject;
}
public GitlabCommitStatus createCommitStatus(GitlabAPI api, String status, String targetUrl) {
try {
if(getLastCommit()!=null) {
return api.createCommitStatus(sourceProject, checkout_sha, status, checkout_sha, "Jenkins", targetUrl, null);
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private String before;
private String after;

View File

@ -40,7 +40,6 @@ import jenkins.model.ParameterizedJobMixIn;
import jenkins.triggers.SCMTriggerItem;
import jenkins.triggers.SCMTriggerItem.SCMTriggerItems;
import net.sf.json.JSONObject;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jgit.transport.RemoteConfig;
@ -82,6 +81,7 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
private boolean ciSkip = true;
private boolean setBuildDescription = true;
private boolean addNoteOnMergeRequest = true;
private boolean addCiMessage = false;
private boolean addVoteOnMergeRequest = true;
private boolean allowAllBranches = false;
private final String includeBranchesSpec;
@ -89,14 +89,15 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
private boolean acceptMergeRequestOnSuccess = false;
@DataBoundConstructor
public GitLabPushTrigger(boolean triggerOnPush, boolean triggerOnMergeRequest, String triggerOpenMergeRequestOnPush, boolean ciSkip, boolean setBuildDescription, boolean addNoteOnMergeRequest, boolean addVoteOnMergeRequest, boolean acceptMergeRequestOnSuccess, boolean allowAllBranches,
public GitLabPushTrigger(boolean triggerOnPush, boolean triggerOnMergeRequest, String triggerOpenMergeRequestOnPush, boolean ciSkip, boolean setBuildDescription, boolean addNoteOnMergeRequest, boolean addCiMessage, boolean addVoteOnMergeRequest, boolean acceptMergeRequestOnSuccess, boolean allowAllBranches,
String includeBranchesSpec, String excludeBranchesSpec) {
this.triggerOnPush = triggerOnPush;
this.triggerOnMergeRequest = triggerOnMergeRequest;
this.triggerOpenMergeRequestOnPush = triggerOpenMergeRequestOnPush;
this.ciSkip = ciSkip;
this.setBuildDescription = setBuildDescription;
this.addNoteOnMergeRequest = addNoteOnMergeRequest;
this.addNoteOnMergeRequest = addNoteOnMergeRequest;
this.addCiMessage = addCiMessage;
this.addVoteOnMergeRequest = addVoteOnMergeRequest;
this.allowAllBranches = allowAllBranches;
this.includeBranchesSpec = includeBranchesSpec;
@ -128,10 +129,18 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
return addVoteOnMergeRequest;
}
public boolean getAcceptMergeRequestOnSuccess() {
return acceptMergeRequestOnSuccess;
}
public boolean getAllowAllBranches() {
return allowAllBranches;
}
public boolean getAddCiMessage() {
return addCiMessage;
}
public boolean getCiSkip() {
return ciSkip;
}
@ -200,20 +209,18 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
} else {
LOGGER.log(Level.INFO, "GitLab Push Request detected in {0}. Job is already in the queue.", job.getName());
}
if(addCiMessage) {
req.createCommitStatus(getDescriptor().getGitlab().instance(), "pending", Jenkins.getInstance().getRootUrl() + job.getUrl());
}
}
private GitLabPushCause createGitLabPushCause(GitLabPushRequest req) {
GitLabPushCause cause;
String triggeredByUser;
if (req.getCommits().size() > 0){
triggeredByUser = req.getCommits().get(0).getAuthor().getName();
} else {
triggeredByUser = req.getUser_name();
}
try {
cause = new GitLabPushCause(triggeredByUser, getLogFile());
cause = new GitLabPushCause(req, getLogFile());
} catch (IOException ex) {
cause = new GitLabPushCause(triggeredByUser);
cause = new GitLabPushCause(req);
}
return cause;
}
@ -230,13 +237,6 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
values.put("gitlabTargetBranch", new StringParameterValue("gitlabTargetBranch", branch));
values.put("gitlabBranch", new StringParameterValue("gitlabBranch", branch));
if (job instanceof AbstractProject<?,?>){
LOGGER.log(Level.INFO, "Trying to get name and URL for job: {0} using project {1} (push)", new String[]{job.getName(), ((AbstractProject<?, ?>) job).getRootProject().getName()});
}else{
LOGGER.log(Level.INFO, "Trying to get name and URL for job: {0} (push)", new String[]{job.getName()});
}
values.put("gitlabSourceRepoName", new StringParameterValue("gitlabSourceRepoName", getDesc().getSourceRepoNameDefault(job)));
values.put("gitlabSourceRepoURL", new StringParameterValue("gitlabSourceRepoURL", getDesc().getSourceRepoURLDefault(job).toString()));
values.put("gitlabActionType", new StringParameterValue("gitlabActionType", "PUSH"));
values.put("gitlabUserName", new StringParameterValue("gitlabUserName", req.getCommits().get(0).getAuthor().getName()));
values.put("gitlabUserEmail", new StringParameterValue("gitlabUserEmail", req.getCommits().get(0).getAuthor().getEmail()));
@ -244,6 +244,23 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
values.put("gitlabMergeRequestId", new StringParameterValue("gitlabMergeRequestId", ""));
values.put("gitlabMergeRequestAssignee", new StringParameterValue("gitlabMergeRequestAssignee", ""));
LOGGER.log(Level.INFO, "Trying to get name and URL for job: {0}", job.getName());
String sourceRepoName = getDesc().getSourceRepoNameDefault(job);
String sourceRepoURL = getDesc().getSourceRepoURLDefault(job).toString();
if (!getDescriptor().getGitlabHostUrl().isEmpty()) {
// Get source repository if communication to Gitlab is possible
try {
sourceRepoName = req.getSourceProject(getDesc().getGitlab()).getPathWithNamespace();
sourceRepoURL = req.getSourceProject(getDesc().getGitlab()).getSshUrl();
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "Could not fetch source project''s data from Gitlab. '('{0}':' {1}')'", new String[]{ex.toString(), ex.getMessage()});
}
}
values.put("gitlabSourceRepoName", new StringParameterValue("gitlabSourceRepoName", sourceRepoName));
values.put("gitlabSourceRepoURL", new StringParameterValue("gitlabSourceRepoURL", sourceRepoURL));
List<ParameterValue> listValues = new ArrayList<ParameterValue>(values.values());
ParametersAction parametersAction = new ParametersAction(listValues);
@ -301,6 +318,10 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
} else {
LOGGER.log(Level.INFO, "GitLab Merge Request detected in {0}. Job is already in the queue.", job.getName());
}
if(addCiMessage) {
req.createCommitStatus(getDescriptor().getGitlab().instance(), "pending", Jenkins.getInstance().getRootUrl() + job.getUrl());
}
}
private GitLabMergeCause createGitLabMergeCause(GitLabMergeRequest req) {
@ -393,12 +414,23 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
}
}
public void onCompleted(Run build){
Cause mCause= build.getCause(GitLabMergeCause.class);
public void onCompleted(Run run){
Cause mCause= run.getCause(GitLabMergeCause.class);
if (mCause != null && mCause instanceof GitLabMergeCause) {
onCompleteMergeRequest(build,(GitLabMergeCause) mCause);
onCompleteMergeRequest(run, (GitLabMergeCause) mCause);
}
Cause pCause= run.getCause(GitLabPushCause.class);
if (pCause != null && pCause instanceof GitLabPushCause) {
onCompletedPushRequest(run, (GitLabPushCause) pCause);
}
}
private void onCompletedPushRequest(Run run, GitLabPushCause cause) {
if(addCiMessage) {
cause.getPushRequest().createCommitStatus(this.getDescriptor().getGitlab().instance(), run.getResult()==Result.SUCCESS?"success":"failure", Jenkins.getInstance().getRootUrl() + run.getUrl());
}
}
private void onCompleteMergeRequest(Run run,GitLabMergeCause cause){
@ -437,10 +469,35 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
}
}
if(addCiMessage) {
cause.getMergeRequest().createCommitStatus(this.getDescriptor().getGitlab().instance(), run.getResult()==Result.SUCCESS?"success":"failure", Jenkins.getInstance().getRootUrl() + run.getUrl());
}
}
public void onStarted(Run run) {
setBuildCauseInJob(run);
Cause mCause= run.getCause(GitLabMergeCause.class);
if (mCause != null && mCause instanceof GitLabMergeCause) {
onStartedMergeRequest(run, (GitLabMergeCause) mCause);
}
Cause pCause= run.getCause(GitLabPushCause.class);
if (pCause != null && pCause instanceof GitLabPushCause) {
onStartedPushRequest(run, (GitLabPushCause) pCause);
}
}
private void onStartedPushRequest(Run run, GitLabPushCause cause) {
if(addCiMessage) {
cause.getPushRequest().createCommitStatus(this.getDescriptor().getGitlab().instance(), "running", Jenkins.getInstance().getRootUrl() + run.getUrl());
}
}
private void onStartedMergeRequest(Run run, GitLabMergeCause cause) {
if(addCiMessage) {
cause.getMergeRequest().createCommitStatus(this.getDescriptor().getGitlab().instance(), "running", Jenkins.getInstance().getRootUrl() + run.getUrl());
}
}
private String getSourceBranch(GitLabRequest req) {

View File

@ -14,8 +14,10 @@ import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import org.gitlab.api.GitlabAPI;
import org.gitlab.api.models.GitlabCommitStatus;
public class GitLabRequest {
public abstract class GitLabRequest {
protected enum Builder {
INSTANCE;
private final Gson gson;
@ -51,4 +53,6 @@ public class GitLabRequest {
}
}
public abstract GitlabCommitStatus createCommitStatus(GitlabAPI api, String status, String targetUrl);
}

View File

@ -1,6 +1,6 @@
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<f:entry title="Build on Merge Request Events" field="triggerOnMergeRequest">
<f:entry title="Build on Merge Request Events" field="triggerOnMergeRequest">
<f:checkbox default="true" />
</f:entry>
<f:entry title="Build on Push Events" field="triggerOnPush">
@ -17,23 +17,31 @@
</f:entry>
<f:entry title="Add note with build status on merge requests" field="addNoteOnMergeRequest">
<f:checkbox default="true" />
</f:entry>
<f:entry title="Use GitLab CI features (GitLab 8.1 required!)" field="addCiMessage" help="/plugin/gitlab-plugin/help/help-gitlab8.1CI.html">
<f:checkbox default="false"/>
</f:entry>
<f:entry title="Vote added to note with build status on merge requests" field="addVoteOnMergeRequest">
<f:checkbox default="true" />
</f:entry>
<f:entry title="Accept merge request on success" field="acceptMergeRequestOnSuccess">
<f:checkbox default="true" />
<f:checkbox default="false" />
</f:entry>
<f:entry title="All allow all branches (Ignoring Filtered Branches)" field="allowAllBranches">
<f:checkbox default="false" />
</f:entry>
<f:optionalBlock title="Filter branches" help="/plugin/gitlab-plugin/help/help-allowedBranches.html"
inline="true" checked="${not (empty(instance.includeBranchesSpec) and empty(instance.excludeBranchesSpec))}">
<f:entry title="Include">
<f:block>
<table style="margin-left:10px">
<f:optionalBlock title="Filter branches" help="/plugin/gitlab-plugin/help/help-allowedBranches.html" inline="true" checked="${not (empty(instance.includeBranchesSpec) and empty(instance.excludeBranchesSpec))}">
<f:entry title="Include">
<f:textbox field="includeBranchesSpec" autocompleteDelimChar="," />
</f:entry>
<f:entry title="Exclude">
</f:entry>
<f:entry title="Exclude">
<f:textbox field="excludeBranchesSpec" autocompleteDelimChar="," />
</f:entry>
</f:optionalBlock>
</j:jelly>
</f:entry>
</f:optionalBlock>
</table>
</f:block>
</j:jelly>

View File

@ -0,0 +1,3 @@
<div>
Enable GitLab 8.1 Continuous Integration feature. <b>DO NOT ENABLE IF YOU'RE USING A VERSION BEFORE GITLAB 8.1</b>.
</div>