├── .gitignore ├── README.md ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── jenkinsci │ │ └── plugins │ │ └── gitbucket │ │ ├── GitBucketBrowser.java │ │ ├── GitBucketBuildTriggerBadgeProvider.java │ │ ├── GitBucketLinkAction.java │ │ ├── GitBucketLinkAnnotator.java │ │ ├── GitBucketProjectProperty.java │ │ ├── GitBucketPushRequest.java │ │ ├── GitBucketPushTrigger.java │ │ ├── GitBucketUtil.java │ │ └── GitBucketWebHook.java ├── resources │ ├── index.jelly │ └── org │ │ └── jenkinsci │ │ └── plugins │ │ └── gitbucket │ │ ├── GitBucketBrowser │ │ └── config.jelly │ │ ├── GitBucketProjectProperty │ │ └── config.jelly │ │ └── GitBucketPushTrigger │ │ ├── GitBucketWebHookPollingAction │ │ └── index.jelly │ │ ├── config.jelly │ │ └── help-passThroughGitCommit.html └── webapp │ ├── help │ └── help-trigger.html │ └── images │ └── 24x24 │ ├── gitbucket-log.png │ └── gitbucket.png └── test ├── java └── org │ └── jenkinsci │ └── plugins │ └── gitbucket │ ├── GitBucketBrowserTest.java │ ├── GitBucketLinkAnnotatorTest.java │ ├── GitBucketProjectPropertyTest.java │ ├── GitBucketPushRequestTest.java │ ├── GitBucketWebHookCompatibleTest.java │ ├── GitBucketWebHookCrumbExclusionTest.java │ └── GitBucketWebHookTest.java └── resources └── org └── jenkinsci └── plugins └── gitbucket └── WebHookPayload.json /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | work 3 | .classpath 4 | .project 5 | .settings 6 | .idea 7 | nb-configuration.xml 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | GitBucket Plugin 2 | ================= 3 | 4 | [![Build Status](https://jenkins.ci.cloudbees.com/job/plugins/job/gitbucket-plugin/badge/icon)](https://jenkins.ci.cloudbees.com/job/plugins/job/gitbucket-plugin/) 5 | 6 | This plugin integrates [GitBucket](https://github.com/takezoe/gitbucket) to Jenkins. 7 | 8 | 9 | - The keywords in changelogs are hyperlinked to the corresponding Issue pages, Pull Requests pages and Wiki pages. 10 | - Hyperlinks to the changeset, diff pages. 11 | - Trigger a build when a change is pushed to GitBucket. 12 | - [Build Trigger Badge Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Build+Trigger+Badge+Plugin) support. 13 | 14 | 15 | For more information, see [the Wiki page](https://wiki.jenkins-ci.org/display/JENKINS/GitBucket+Plugin). -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | org.jenkins-ci.plugins 6 | plugin 7 | 1.609.3 8 | 9 | 10 | gitbucket 11 | GitBucket Plugin 12 | 0.9-SNAPSHOT 13 | hpi 14 | 15 | http://wiki.jenkins-ci.org/display/JENKINS/GitBucket+Plugin 16 | 17 | 18 | The MIT license 19 | http://www.opensource.org/licenses/mit-license.php 20 | repo 21 | 22 | 23 | 24 | 25 | 26 | ssogabe 27 | Seiji Sogabe 28 | 29 | 30 | 31 | 32 | scm:git:git://github.com/jenkinsci/gitbucket-plugin.git 33 | scm:git:git@github.com:jenkinsci/gitbucket-plugin.git 34 | https://github.com/jenkinsci/gitbucket-plugin 35 | HEAD 36 | 37 | 38 | 39 | 40 | 41 | org.jacoco 42 | jacoco-maven-plugin 43 | 0.7.4.201502262128 44 | 45 | ${project.build.directory}/coverage-reports/jacoco-ut.exec 46 | ${project.build.directory}/coverage-reports/jacoco-ut.exec 47 | 48 | 49 | 50 | pre-unit-test 51 | 52 | prepare-agent 53 | 54 | 55 | 56 | post-unit-test 57 | package 58 | 59 | report 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.jenkins-ci.plugins 70 | matrix-project 71 | 1.4.1 72 | 73 | 74 | org.jenkins-ci.plugins 75 | git 76 | 2.4.0 77 | 78 | 79 | org.jenkins-ci.plugins 80 | multiple-scms 81 | 0.5 82 | true 83 | 84 | 85 | org.jenkins-ci.plugins 86 | buildtriggerbadge 87 | 2.1 88 | true 89 | 90 | 91 | junit 92 | junit 93 | 4.12 94 | test 95 | 96 | 97 | org.mockito 98 | mockito-all 99 | 1.10.19 100 | test 101 | 102 | 103 | 104 | 105 | 106 | repo.jenkins-ci.org 107 | http://repo.jenkins-ci.org/public/ 108 | 109 | 110 | 111 | 112 | 113 | repo.jenkins-ci.org 114 | http://repo.jenkins-ci.org/public/ 115 | 116 | 117 | 118 | 119 | UTF-8 120 | UTF-8 121 | 122 | 123 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/gitbucket/GitBucketBrowser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, Seiji Sogabe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import hudson.Extension; 27 | import hudson.model.Descriptor; 28 | import hudson.plugins.git.GitChangeSet; 29 | import hudson.plugins.git.GitChangeSet.Path; 30 | import hudson.plugins.git.browser.GitRepositoryBrowser; 31 | import hudson.scm.EditType; 32 | import hudson.scm.RepositoryBrowser; 33 | import java.io.IOException; 34 | import java.net.MalformedURLException; 35 | import java.net.URL; 36 | import java.util.ArrayList; 37 | import java.util.Collections; 38 | import java.util.List; 39 | import net.sf.json.JSONObject; 40 | import org.kohsuke.stapler.DataBoundConstructor; 41 | import org.kohsuke.stapler.StaplerRequest; 42 | 43 | /** 44 | * GitBucket Browser URLs 45 | */ 46 | public class GitBucketBrowser extends GitRepositoryBrowser { 47 | 48 | private static final long serialVersionUID = 1L; 49 | 50 | @DataBoundConstructor 51 | public GitBucketBrowser(String url) throws MalformedURLException { 52 | super(url); 53 | } 54 | 55 | @Override 56 | public URL getChangeSetLink(GitChangeSet changeSet) throws IOException { 57 | return new URL(getUrl(), "commit/" + changeSet.getId()); 58 | } 59 | 60 | @Override 61 | public URL getDiffLink(Path path) throws IOException { 62 | if (path.getEditType() != EditType.EDIT || path.getSrc() == null || path.getDst() == null 63 | || path.getChangeSet().getParentCommit() == null) { 64 | return null; 65 | } 66 | return getDiffLinkRegardlessOfEditType(path); 67 | } 68 | 69 | private URL getDiffLinkRegardlessOfEditType(Path path) throws IOException { 70 | GitChangeSet changeSet = path.getChangeSet(); 71 | List affectedPaths = new ArrayList(changeSet.getAffectedPaths()); 72 | Collections.sort(affectedPaths); 73 | String pathAsString = path.getPath(); 74 | int i = Collections.binarySearch(affectedPaths, pathAsString); 75 | assert i >= 0; 76 | return new URL(getChangeSetLink(changeSet), "#diff-" + String.valueOf(i)); 77 | } 78 | 79 | @Override 80 | public URL getFileLink(Path path) throws IOException { 81 | if (path.getEditType().equals(EditType.DELETE)) { 82 | return getDiffLinkRegardlessOfEditType(path); 83 | } else { 84 | String spec = "blob/" + path.getChangeSet().getId() + "/" + path.getPath(); 85 | return new URL(getUrl(), spec); 86 | } 87 | } 88 | 89 | @Extension 90 | public static class GitBucketBrowserDescriptor extends Descriptor> { 91 | 92 | @Override 93 | public String getDisplayName() { 94 | return "GitBucket"; 95 | } 96 | 97 | @Override 98 | public GitBucketBrowser newInstance(StaplerRequest req, JSONObject jsonObject) throws FormException { 99 | return req.bindJSON(GitBucketBrowser.class, jsonObject); 100 | } 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/gitbucket/GitBucketBuildTriggerBadgeProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2015 Seiji Sogabe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software withoutcd came restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import hudson.Extension; 27 | import hudson.model.Cause; 28 | import org.jenkinsci.plugins.buildtriggerbadge.provider.BuildTriggerBadgeProvider; 29 | 30 | @Extension(optional=true) 31 | public class GitBucketBuildTriggerBadgeProvider extends BuildTriggerBadgeProvider { 32 | 33 | 34 | @Override 35 | public String provideIcon(Cause cause) { 36 | if (cause instanceof GitBucketPushTrigger.GitBucketPushCause) { 37 | return "/plugin/gitbucket/images/24x24/gitbucket.png"; 38 | } 39 | 40 | return null; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/gitbucket/GitBucketLinkAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, Seiji Sogabe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import hudson.model.Action; 27 | 28 | /** 29 | * Add the GitBucket Icon/Link to the sidebar. 30 | * 31 | * @author sogabe 32 | */ 33 | public class GitBucketLinkAction implements Action { 34 | 35 | private final transient GitBucketProjectProperty property; 36 | 37 | public GitBucketLinkAction(GitBucketProjectProperty property) { 38 | this.property = property; 39 | } 40 | 41 | @Override 42 | public String getIconFileName() { 43 | return "/plugin/gitbucket/images/24x24/gitbucket.png"; 44 | } 45 | 46 | @Override 47 | public String getDisplayName() { 48 | return "GitBucket"; 49 | } 50 | 51 | @Override 52 | public String getUrlName() { 53 | return property.getUrl(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/gitbucket/GitBucketLinkAnnotator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, Seiji Sogabe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import hudson.Extension; 27 | import hudson.MarkupText; 28 | import hudson.MarkupText.SubText; 29 | import hudson.model.AbstractBuild; 30 | import hudson.model.Run; 31 | import hudson.scm.ChangeLogAnnotator; 32 | import hudson.scm.ChangeLogSet; 33 | import java.util.regex.Pattern; 34 | 35 | /** 36 | * Creates HTML link for GitBucket issues. 37 | * 38 | * @author sogabe 39 | */ 40 | @Extension 41 | public class GitBucketLinkAnnotator extends ChangeLogAnnotator { 42 | 43 | @Override 44 | public void annotate(Run build, ChangeLogSet.Entry change, MarkupText text) { 45 | GitBucketProjectProperty gpp = GitBucketProjectProperty.get(build); 46 | if (gpp == null) { 47 | return; 48 | } 49 | if (!gpp.isLinkEnabled()) { 50 | return; 51 | } 52 | 53 | String url = gpp.getUrl(); 54 | annotate(text, url + '/'); 55 | } 56 | 57 | @Deprecated 58 | @Override 59 | public void annotate(AbstractBuild build, ChangeLogSet.Entry change, MarkupText text) { 60 | annotate((Run) build, change, text); 61 | } 62 | 63 | void annotate(MarkupText text, String url) { 64 | for (LinkMarkup markup : MARKUPS) { 65 | markup.process(text, url); 66 | } 67 | } 68 | 69 | private static final LinkMarkup[] MARKUPS = new LinkMarkup[]{ 70 | new LinkMarkup("close\\s+#?(\\d+)", "issues/$1"), 71 | new LinkMarkup("closes\\s+#?(\\d+)", "issues/$1"), 72 | new LinkMarkup("closed\\s+#?(\\d+)", "issues/$1"), 73 | new LinkMarkup("fix\\s+#?(\\d+)", "issues/$1"), 74 | new LinkMarkup("fixes\\s+#?(\\d+)", "issues/$1"), 75 | new LinkMarkup("fixed\\s+#?(\\d+)", "issues/$1"), 76 | new LinkMarkup("resolve\\s+#?(\\d+)", "issues/$1"), 77 | new LinkMarkup("resolves\\s+#?(\\d+)", "issues/$1"), 78 | new LinkMarkup("resolved\\s+#?(\\d+)", "issues/$1"), 79 | new LinkMarkup("refs\\s+#?(\\d+)", "issues/$1"), 80 | new LinkMarkup("issue\\s+#?(\\d+)", "issues/$1"), 81 | new LinkMarkup("pull\\s+#?(\\d+)", "pulls/$1"), 82 | new LinkMarkup("wiki\\s+(\\w+)", "wiki/$1") 83 | }; 84 | 85 | private static final class LinkMarkup { 86 | 87 | private final Pattern pattern; 88 | 89 | private final String href; 90 | 91 | LinkMarkup(String pattern, String href) { 92 | this.pattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE); 93 | this.href = href; 94 | } 95 | 96 | void process(MarkupText text, String url) { 97 | for (SubText st : text.findTokens(pattern)) { 98 | st.surroundWith( 99 | "", 100 | ""); 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/gitbucket/GitBucketProjectProperty.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, Seiji Sogabe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import hudson.Extension; 27 | import hudson.matrix.MatrixRun; 28 | import hudson.model.AbstractBuild; 29 | import hudson.model.AbstractProject; 30 | import hudson.model.Action; 31 | import hudson.model.Job; 32 | import hudson.model.JobProperty; 33 | import hudson.model.JobPropertyDescriptor; 34 | import hudson.model.Run; 35 | import java.util.Collection; 36 | import java.util.Collections; 37 | import org.kohsuke.stapler.DataBoundConstructor; 38 | 39 | /** 40 | * Project property 41 | * 42 | * @author sogabe 43 | */ 44 | public class GitBucketProjectProperty extends JobProperty> { 45 | 46 | private final String url; 47 | 48 | private final boolean linkEnabled; 49 | 50 | public String getUrl() { 51 | return url; 52 | } 53 | 54 | public boolean isLinkEnabled() { 55 | return linkEnabled; 56 | } 57 | 58 | @DataBoundConstructor 59 | public GitBucketProjectProperty(String url, boolean linkEnabled) { 60 | this.url = GitBucketUtil.trimEndSlash(url); 61 | this.linkEnabled = linkEnabled; 62 | } 63 | 64 | @Override 65 | public Collection getJobActions(AbstractProject job) { 66 | if (url == null) { 67 | return Collections.emptyList(); 68 | } 69 | return Collections.singletonList(new GitBucketLinkAction(this)); 70 | } 71 | 72 | public static GitBucketProjectProperty get(Run build) { 73 | if (build == null) { 74 | return null; 75 | } 76 | Job job; 77 | if (build instanceof MatrixRun) { 78 | job = ((MatrixRun) build).getProject().getParent(); 79 | } else { 80 | job = build.getParent(); 81 | } 82 | return job.getProperty(GitBucketProjectProperty.class); 83 | } 84 | 85 | @Deprecated 86 | public static GitBucketProjectProperty get(AbstractBuild build) { 87 | return get((Run) build); 88 | } 89 | 90 | @Extension 91 | public static final class DescriptorImpl extends JobPropertyDescriptor { 92 | 93 | @Override 94 | public String getDisplayName() { 95 | return "GitBucket"; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/gitbucket/GitBucketPushRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2013 Seiji Sogabe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import java.util.HashMap; 27 | import java.util.List; 28 | import java.util.Map; 29 | import net.sf.json.JSONObject; 30 | import net.sf.json.JsonConfig; 31 | import net.sf.json.util.JavaIdentifierTransformer; 32 | import org.apache.commons.lang.builder.ToStringBuilder; 33 | import org.apache.commons.lang.builder.ToStringStyle; 34 | 35 | /** 36 | * Represents for WebHook payload 37 | * 38 | * @author sogabe 39 | */ 40 | public class GitBucketPushRequest { 41 | 42 | private User pusher; 43 | 44 | private String ref; 45 | 46 | private List commits; 47 | 48 | private Repository repository; 49 | 50 | public static GitBucketPushRequest create(String payload) { 51 | if (payload == null) { 52 | throw new IllegalArgumentException("payload should not be null"); 53 | } 54 | return create(JSONObject.fromObject(payload)); 55 | } 56 | 57 | public static GitBucketPushRequest create(JSONObject payload) { 58 | if (payload == null || payload.isNullObject()) { 59 | throw new IllegalArgumentException("payload should not be null"); 60 | } 61 | 62 | JsonConfig config = createJsonConfig(); 63 | return (GitBucketPushRequest) JSONObject.toBean(payload, config); 64 | } 65 | 66 | private static JsonConfig createJsonConfig() { 67 | JsonConfig config = new JsonConfig(); 68 | config.setRootClass(GitBucketPushRequest.class); 69 | 70 | Map> classMap = new HashMap>(); 71 | classMap.put("commits", Commit.class); 72 | classMap.put("added", String.class); 73 | classMap.put("removed", String.class); 74 | classMap.put("modified", String.class); 75 | config.setClassMap(classMap); 76 | 77 | config.setJavaIdentifierTransformer(new JavaIdentifierTransformer() { 78 | 79 | @Override 80 | public String transformToJavaIdentifier(String param) { 81 | if (param == null) { 82 | return null; 83 | } 84 | if ("private".equals(param)) { 85 | return "private_"; 86 | } 87 | // TODO: can't we use JavaIdentifierTransformer.CAMEL_CASE ? 88 | if("clone_url".equals(param)) { 89 | return "cloneUrl"; 90 | } 91 | return param; 92 | } 93 | 94 | }); 95 | 96 | return config; 97 | } 98 | 99 | public GitBucketPushRequest() { 100 | } 101 | 102 | public User getPusher() { 103 | return pusher; 104 | } 105 | 106 | public void setPusher(User pusher) { 107 | this.pusher = pusher; 108 | } 109 | 110 | public String getRef() { 111 | return ref; 112 | } 113 | 114 | public void setRef(String ref) { 115 | this.ref = ref; 116 | } 117 | 118 | public List getCommits() { 119 | return commits; 120 | } 121 | 122 | public Commit getLastCommit() { 123 | if (commits.isEmpty()) { 124 | return null; 125 | } 126 | return commits.get(commits.size() - 1); 127 | } 128 | 129 | public void setCommits(List commits) { 130 | this.commits = commits; 131 | } 132 | 133 | public Repository getRepository() { 134 | return repository; 135 | } 136 | 137 | public void setRepository(Repository repository) { 138 | this.repository = repository; 139 | } 140 | 141 | @Override 142 | public String toString() { 143 | return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); 144 | } 145 | 146 | public static class Repository { 147 | 148 | private String name; 149 | 150 | private String url; 151 | 152 | private String cloneUrl; 153 | 154 | private String description; 155 | 156 | private Integer forks; 157 | 158 | private boolean private_; 159 | 160 | private User owner; 161 | 162 | public Repository() { 163 | } 164 | 165 | public String getName() { 166 | return name; 167 | } 168 | 169 | public void setName(String name) { 170 | this.name = name; 171 | } 172 | 173 | public String getUrl() { 174 | return url; 175 | } 176 | 177 | public void setUrl(String url) { 178 | this.url = url; 179 | } 180 | 181 | public String getCloneUrl() { 182 | return cloneUrl; 183 | } 184 | 185 | public void setCloneUrl(String cloneUrl) { 186 | this.cloneUrl = cloneUrl; 187 | } 188 | 189 | public String getDescription() { 190 | return description; 191 | } 192 | 193 | public void setDescription(String description) { 194 | this.description = description; 195 | } 196 | 197 | public Integer getForks() { 198 | return forks; 199 | } 200 | 201 | public void setForks(Integer forks) { 202 | this.forks = forks; 203 | } 204 | 205 | public boolean isPrivate_() { 206 | return private_; 207 | } 208 | 209 | public void setPrivate_(boolean private_) { 210 | this.private_ = private_; 211 | } 212 | 213 | public User getOwner() { 214 | return owner; 215 | } 216 | 217 | public void setOwner(User owner) { 218 | this.owner = owner; 219 | } 220 | 221 | @Override 222 | public String toString() { 223 | return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); 224 | } 225 | 226 | } 227 | 228 | public static class Commit { 229 | 230 | private String id; 231 | 232 | private String message; 233 | 234 | private String timestamp; 235 | 236 | private String url; 237 | 238 | private List added; 239 | 240 | private List removed; 241 | 242 | private List modified; 243 | 244 | public Commit() { 245 | } 246 | 247 | public String getId() { 248 | return id; 249 | } 250 | 251 | public void setId(String id) { 252 | this.id = id; 253 | } 254 | 255 | public String getMessage() { 256 | return message; 257 | } 258 | 259 | public void setMessage(String message) { 260 | this.message = message; 261 | } 262 | 263 | public String getTimestamp() { 264 | return timestamp; 265 | } 266 | 267 | public void setTimestamp(String timestamp) { 268 | this.timestamp = timestamp; 269 | } 270 | 271 | public String getUrl() { 272 | return url; 273 | } 274 | 275 | public void setUrl(String url) { 276 | this.url = url; 277 | } 278 | 279 | public List getAdded() { 280 | return added; 281 | } 282 | 283 | public void setAdded(List added) { 284 | this.added = added; 285 | } 286 | 287 | public List getRemoved() { 288 | return removed; 289 | } 290 | 291 | public void setRemoved(List removed) { 292 | this.removed = removed; 293 | } 294 | 295 | public List getModified() { 296 | return modified; 297 | } 298 | 299 | public void setModified(List modified) { 300 | this.modified = modified; 301 | } 302 | 303 | @Override 304 | public String toString() { 305 | return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); 306 | } 307 | 308 | } 309 | 310 | public static class User { 311 | 312 | private String name; 313 | 314 | private String email; 315 | 316 | public User() { 317 | } 318 | 319 | public String getName() { 320 | return name; 321 | } 322 | 323 | public void setName(String name) { 324 | this.name = name; 325 | } 326 | 327 | public String getEmail() { 328 | return email; 329 | } 330 | 331 | public void setEmail(String email) { 332 | this.email = email; 333 | } 334 | 335 | @Override 336 | public String toString() { 337 | return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); 338 | } 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/gitbucket/GitBucketPushTrigger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, Seiji Sogabe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import hudson.Extension; 27 | import hudson.Util; 28 | import hudson.console.AnnotatedLargeText; 29 | import hudson.model.AbstractProject; 30 | import hudson.model.Action; 31 | import hudson.model.Item; 32 | import hudson.plugins.git.RevisionParameterAction; 33 | import hudson.triggers.SCMTrigger.SCMTriggerCause; 34 | import hudson.triggers.Trigger; 35 | import hudson.triggers.TriggerDescriptor; 36 | import hudson.util.SequentialExecutionQueue; 37 | import hudson.util.StreamTaskListener; 38 | import java.io.File; 39 | import java.io.IOException; 40 | import java.io.PrintStream; 41 | import java.nio.charset.Charset; 42 | import java.text.DateFormat; 43 | import java.util.ArrayList; 44 | import java.util.Collection; 45 | import java.util.Collections; 46 | import java.util.Date; 47 | import java.util.List; 48 | import java.util.logging.Level; 49 | import java.util.logging.Logger; 50 | import jenkins.model.Jenkins.MasterComputer; 51 | import org.apache.commons.jelly.XMLOutput; 52 | import org.jenkinsci.plugins.gitbucket.GitBucketPushRequest.Commit; 53 | import org.kohsuke.stapler.DataBoundConstructor; 54 | 55 | /** 56 | * Triggers a build when we receive a GitBucket WebHook. 57 | * 58 | * @author sogabe 59 | */ 60 | public class GitBucketPushTrigger extends Trigger> { 61 | 62 | private boolean passThroughGitCommit; 63 | 64 | @DataBoundConstructor 65 | public GitBucketPushTrigger(boolean passThroughGitCommit) { 66 | this.passThroughGitCommit = passThroughGitCommit; 67 | } 68 | 69 | public boolean isPassThroughGitCommit() { 70 | return passThroughGitCommit; 71 | } 72 | 73 | public void onPost(final GitBucketPushRequest req) { 74 | getDescriptor().queue.execute(new Runnable() { 75 | private boolean polling() { 76 | try { 77 | StreamTaskListener listener = new StreamTaskListener(getLogFile()); 78 | 79 | try { 80 | PrintStream logger = listener.getLogger(); 81 | 82 | long start = System.currentTimeMillis(); 83 | logger.println("Started on " 84 | + DateFormat.getDateTimeInstance().format(new Date())); 85 | boolean result = job.poll(listener).hasChanges(); 86 | logger.println("Done. Took " 87 | + Util.getTimeSpanString(System.currentTimeMillis() - start)); 88 | 89 | if (result) { 90 | logger.println("Changes found"); 91 | } else { 92 | logger.println("No changes"); 93 | } 94 | 95 | return result; 96 | } catch (Error e) { 97 | e.printStackTrace(listener.error("Failed to record SCM polling")); 98 | LOGGER.log(Level.SEVERE, "Failed to record SCM polling", e); 99 | throw e; 100 | } catch (RuntimeException e) { 101 | e.printStackTrace(listener.error("Failed to record SCM polling")); 102 | LOGGER.log(Level.SEVERE, "Failed to record SCM polling", e); 103 | throw e; 104 | } finally { 105 | listener.closeQuietly(); 106 | } 107 | } catch (IOException e) { 108 | LOGGER.log(Level.SEVERE, "Failed to record SCM polling", e); 109 | } 110 | 111 | return false; 112 | } 113 | 114 | @Override 115 | public void run() { 116 | LOGGER.log(Level.INFO, "{0} triggered.", job.getName()); 117 | if (polling()) { 118 | String name = " #" + job.getNextBuildNumber(); 119 | GitBucketPushCause cause = createGitBucketPushCause(req); 120 | Action[] actions = createActions(req); 121 | if (job.scheduleBuild(job.getQuietPeriod(), cause, actions)) { 122 | LOGGER.log(Level.INFO, "SCM changes detected in {0}. Triggering {1}", 123 | new String[]{job.getName(), name}); 124 | } else { 125 | LOGGER.log(Level.INFO, "SCM changes detected in {0}. Job is already in the queue.", 126 | job.getName()); 127 | } 128 | } 129 | } 130 | 131 | private GitBucketPushCause createGitBucketPushCause(GitBucketPushRequest req) { 132 | GitBucketPushCause cause; 133 | String triggeredByUser = req.getPusher().getName(); 134 | try { 135 | cause = new GitBucketPushCause(triggeredByUser, getLogFile()); 136 | } catch (IOException ex) { 137 | cause = new GitBucketPushCause(triggeredByUser); 138 | } 139 | return cause; 140 | } 141 | 142 | private Action[] createActions(GitBucketPushRequest req) { 143 | List actions = new ArrayList(); 144 | 145 | if (passThroughGitCommit) { 146 | Commit lastCommit = req.getLastCommit(); 147 | actions.add(new RevisionParameterAction(lastCommit.getId(), false)); 148 | } 149 | 150 | return actions.toArray(new Action[0]); 151 | } 152 | }); 153 | } 154 | 155 | public static class GitBucketPushCause extends SCMTriggerCause { 156 | 157 | private final String pushedBy; 158 | 159 | public GitBucketPushCause(String pushedBy) { 160 | this(pushedBy, ""); 161 | } 162 | 163 | public GitBucketPushCause(String pushedBy, File logFile) throws IOException { 164 | super(logFile); 165 | this.pushedBy = pushedBy; 166 | } 167 | 168 | public GitBucketPushCause(String pushedBy, String pollingLog) { 169 | super(pollingLog); 170 | this.pushedBy = pushedBy; 171 | } 172 | 173 | @Override 174 | public String getShortDescription() { 175 | if (pushedBy == null) { 176 | return "Started by GitBucket push"; 177 | } else { 178 | return String.format("Started by GitBucket push by %s", pushedBy); 179 | } 180 | } 181 | } 182 | 183 | @Override 184 | public Collection getProjectActions() { 185 | return Collections.singletonList(new GitBucketWebHookPollingAction()); 186 | } 187 | 188 | public class GitBucketWebHookPollingAction implements Action { 189 | 190 | public AbstractProject getOwner() { 191 | return job; 192 | } 193 | 194 | @Override 195 | public String getIconFileName() { 196 | return "/plugin/gitbucket/images/24x24/gitbucket-log.png"; 197 | } 198 | 199 | @Override 200 | public String getDisplayName() { 201 | return "GitBucket Hook Log"; 202 | } 203 | 204 | @Override 205 | public String getUrlName() { 206 | return "GitBucketPollLog"; 207 | } 208 | 209 | public String getLog() throws IOException { 210 | return Util.loadFile(getLogFile()); 211 | } 212 | 213 | public void writeLogTo(XMLOutput out) throws IOException { 214 | new AnnotatedLargeText( 215 | getLogFile(), Charset.defaultCharset(), true, this).writeHtmlTo(0, out.asWriter()); 216 | } 217 | } 218 | 219 | @Override 220 | public GitBucketPushTriggerDescriptor getDescriptor() { 221 | return (GitBucketPushTriggerDescriptor) super.getDescriptor(); 222 | } 223 | 224 | public File getLogFile() { 225 | return new File(job.getRootDir(), "gitbucket-polling.log"); 226 | } 227 | 228 | @Extension 229 | public static class GitBucketPushTriggerDescriptor extends TriggerDescriptor { 230 | 231 | private transient final SequentialExecutionQueue queue 232 | = new SequentialExecutionQueue(MasterComputer.threadPoolForRemoting); 233 | 234 | @Override 235 | public boolean isApplicable(Item item) { 236 | return item instanceof AbstractProject; 237 | } 238 | 239 | @Override 240 | public String getDisplayName() { 241 | return "Build when a change is pushed to GitBucket"; 242 | } 243 | 244 | @Override 245 | public String getHelpFile() { 246 | return "/plugin/gitbucket/help/help-trigger.html"; 247 | } 248 | 249 | } 250 | 251 | private static final Logger LOGGER = Logger.getLogger(GitBucketPushTrigger.class.getName()); 252 | } 253 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/gitbucket/GitBucketUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, Seiji Sogabe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import hudson.Util; 27 | 28 | /** 29 | * Utility 30 | * 31 | * @author sogabe 32 | */ 33 | public final class GitBucketUtil { 34 | 35 | private GitBucketUtil() { 36 | } 37 | 38 | public static String trimEndSlash(String url) { 39 | String u = Util.fixEmptyAndTrim(url); 40 | if (u == null) { 41 | return null; 42 | } 43 | if (!u.endsWith("/")) { 44 | return u; 45 | } 46 | return url.substring(0, u.length() - 1); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/gitbucket/GitBucketWebHook.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, Seiji Sogabe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import hudson.Extension; 27 | import hudson.model.AbstractProject; 28 | import hudson.model.UnprotectedRootAction; 29 | import hudson.plugins.git.GitSCM; 30 | import hudson.scm.SCM; 31 | import hudson.security.ACL; 32 | import hudson.security.csrf.CrumbExclusion; 33 | import java.io.IOException; 34 | import java.util.ArrayList; 35 | import java.util.List; 36 | import java.util.logging.Level; 37 | import java.util.logging.Logger; 38 | import javax.servlet.FilterChain; 39 | import javax.servlet.ServletException; 40 | import javax.servlet.http.HttpServletRequest; 41 | import javax.servlet.http.HttpServletResponse; 42 | import jenkins.model.Jenkins; 43 | import net.sf.json.JSONObject; 44 | import org.acegisecurity.Authentication; 45 | import org.acegisecurity.context.SecurityContextHolder; 46 | import org.eclipse.jgit.transport.RemoteConfig; 47 | import org.eclipse.jgit.transport.URIish; 48 | import org.jenkinsci.plugins.multiplescms.MultiSCM; 49 | import org.kohsuke.stapler.StaplerRequest; 50 | import org.kohsuke.stapler.interceptor.RequirePOST; 51 | 52 | /** 53 | * Receives GitBucket WebHook. 54 | * 55 | * @author sogabe 56 | */ 57 | @Extension 58 | public class GitBucketWebHook implements UnprotectedRootAction { 59 | 60 | public static final String WEBHOOK_URL = "gitbucket-webhook"; 61 | 62 | @Override 63 | public String getIconFileName() { 64 | return null; 65 | } 66 | 67 | @Override 68 | public String getDisplayName() { 69 | return null; 70 | } 71 | 72 | @Override 73 | public String getUrlName() { 74 | return WEBHOOK_URL; 75 | } 76 | 77 | @RequirePOST 78 | public void doIndex(StaplerRequest req) { 79 | String event = req.getHeader("X-Github-Event"); 80 | LOGGER.log(Level.FINE, "WebHook called. event: {0}", event); 81 | if (!"push".equals(event)) { 82 | LOGGER.log(Level.FINE, "Only push event can be accepted."); 83 | return; 84 | } 85 | 86 | String payload = req.getParameter("payload"); 87 | if (payload == null) { 88 | throw new IllegalArgumentException( 89 | "Not intended to be browsed interactively (must specify payload parameter)"); 90 | } 91 | 92 | processPayload(payload); 93 | } 94 | 95 | private void processPayload(String payload) { 96 | JSONObject json = JSONObject.fromObject(payload); 97 | LOGGER.log(Level.FINE, "payload: {0}", json.toString(4)); 98 | 99 | GitBucketPushRequest req = GitBucketPushRequest.create(json); 100 | String repositoryUrl = getRepositoryUrl(req); 101 | if (repositoryUrl == null) { 102 | LOGGER.log(Level.WARNING, "No repository url found."); 103 | return; 104 | } 105 | 106 | Authentication old = SecurityContextHolder.getContext().getAuthentication(); 107 | SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM); 108 | try { 109 | for (AbstractProject job : Jenkins.getInstance().getAllItems(AbstractProject.class)) { 110 | GitBucketPushTrigger trigger = job.getTrigger(GitBucketPushTrigger.class); 111 | if (trigger == null) { 112 | continue; 113 | } 114 | List urls = RepositoryUrlCollector.collect(job); 115 | if (urls.contains(repositoryUrl.toLowerCase())) { 116 | trigger.onPost(req); 117 | } 118 | } 119 | } finally { 120 | SecurityContextHolder.getContext().setAuthentication(old); 121 | } 122 | } 123 | 124 | private String getRepositoryUrl(GitBucketPushRequest req) { 125 | // current gutbucket returns "clone_url", but old one returs "url", 126 | // so we check both for compatbility older than gitbucket 3.1 127 | String url = req.getRepository().getUrl(); 128 | // gitbucket 3.1 or later 129 | String cloneUrl = req.getRepository().getCloneUrl(); 130 | return (cloneUrl != null) ? cloneUrl : url; 131 | } 132 | 133 | private static class RepositoryUrlCollector { 134 | 135 | public static List collect(AbstractProject job) { 136 | List urls = new ArrayList(); 137 | SCM scm = job.getScm(); 138 | if (scm instanceof GitSCM) { 139 | urls.addAll(collect((GitSCM) scm)); 140 | } else if (Jenkins.getInstance().getPlugin("multiple-scms") != null 141 | && scm instanceof MultiSCM) { 142 | MultiSCM multiSCM = (MultiSCM) scm; 143 | List scms = multiSCM.getConfiguredSCMs(); 144 | for (SCM s : scms) { 145 | if (s instanceof GitSCM) { 146 | urls.addAll(collect((GitSCM) s)); 147 | } 148 | } 149 | } 150 | return urls; 151 | } 152 | 153 | private static List collect(GitSCM scm) { 154 | List urls = new ArrayList(); 155 | for (RemoteConfig config : scm.getRepositories()) { 156 | for (URIish uri : config.getURIs()) { 157 | uri = uri.setUser(null).setPass(null); // ignore user and password 158 | String u = uri.toString(); 159 | urls.add(u.trim().toLowerCase()); 160 | } 161 | } 162 | return urls; 163 | } 164 | } 165 | 166 | @Extension 167 | public static class GitBucketWebHookCrumbExclusion extends CrumbExclusion { 168 | 169 | @Override 170 | public boolean process(HttpServletRequest req, HttpServletResponse resp, 171 | FilterChain chain) throws IOException, ServletException { 172 | String pathInfo = req.getPathInfo(); 173 | if (pathInfo != null && pathInfo.equals(getExclusionPath())) { 174 | chain.doFilter(req, resp); 175 | return true; 176 | } 177 | return false; 178 | } 179 | 180 | private String getExclusionPath() { 181 | return '/' + WEBHOOK_URL + '/'; 182 | } 183 | } 184 | 185 | private static final Logger LOGGER = Logger.getLogger(GitBucketWebHook.class.getName()); 186 | } 187 | -------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 |
2 | This plugin integrates GitBucket to Jenkins. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/gitbucket/GitBucketBrowser/config.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/gitbucket/GitBucketProjectProperty/config.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/gitbucket/GitBucketPushTrigger/GitBucketWebHookPollingAction/index.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 |

${%Last GitBucket Push}

30 | 31 | 32 | 33 | ${%Polling has not run yet.} 34 | 35 | 36 |
37 |             
38 |             ${it.writeLogTo(output)}
39 |           
40 |
41 |
42 |
43 |
44 |
-------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/gitbucket/GitBucketPushTrigger/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/gitbucket/GitBucketPushTrigger/help-passThroughGitCommit.html: -------------------------------------------------------------------------------- 1 |
2 | This "parameter" passes the SHA1 commit ID into this job, 3 | and thereby causes the job to check out the specified commit. 4 |
-------------------------------------------------------------------------------- /src/main/webapp/help/help-trigger.html: -------------------------------------------------------------------------------- 1 |
2 | Configure GitBucket to deliver a POST request to your Jenkins at 3 | http://your.jenkins.host/jenkins/gitbucket-webhook/. 4 |
5 | -------------------------------------------------------------------------------- /src/main/webapp/images/24x24/gitbucket-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/gitbucket-plugin/92b576b1c03f7706dd18e3d4a22aff3e88d6c40c/src/main/webapp/images/24x24/gitbucket-log.png -------------------------------------------------------------------------------- /src/main/webapp/images/24x24/gitbucket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/gitbucket-plugin/92b576b1c03f7706dd18e3d4a22aff3e88d6c40c/src/main/webapp/images/24x24/gitbucket.png -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/gitbucket/GitBucketBrowserTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, Seiji Sogabe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import hudson.plugins.git.GitChangeSet; 27 | import hudson.plugins.git.GitChangeSet.Path; 28 | import hudson.scm.EditType; 29 | import java.io.IOException; 30 | import java.net.URL; 31 | import java.util.Arrays; 32 | import java.util.List; 33 | import org.junit.Before; 34 | import org.junit.Test; 35 | import static org.mockito.Mockito.mock; 36 | import static org.mockito.Mockito.when; 37 | import static org.junit.Assert.assertThat; 38 | import static org.hamcrest.CoreMatchers.*; 39 | 40 | /** 41 | * Test for {@link GitBucketBrowser} class. 42 | * 43 | * @author sogabe 44 | */ 45 | public class GitBucketBrowserTest { 46 | 47 | private static final String GITBUCKET_URL = "http://localhost/gitbucket/sogabe/gitbucket-plugin/"; 48 | 49 | private GitBucketBrowser target; 50 | 51 | @Before 52 | public void setUp() throws Exception { 53 | target = new GitBucketBrowser(GITBUCKET_URL); 54 | } 55 | 56 | @Test 57 | public void testGetChangeSetLink() throws IOException { 58 | String id = "1"; 59 | GitChangeSet mockGitChangeSet = mock(GitChangeSet.class); 60 | when(mockGitChangeSet.getId()).thenReturn(id); 61 | 62 | URL actual = target.getChangeSetLink(mockGitChangeSet); 63 | 64 | assertThat(actual.toString(), is(GITBUCKET_URL + "commit/" + id)); 65 | } 66 | 67 | @Test 68 | public void testGetDiffLink_NotEDIT() throws IOException { 69 | EditType editType = EditType.ADD; 70 | Path mockPath = mock(Path.class); 71 | when(mockPath.getEditType()).thenReturn(editType); 72 | 73 | URL actual = target.getDiffLink(mockPath); 74 | 75 | assertThat(actual, nullValue()); 76 | } 77 | 78 | @Test 79 | public void testGetDiffLink_NoSrc() throws IOException { 80 | Path mockPath = mock(Path.class); 81 | when(mockPath.getSrc()).thenReturn(null); 82 | 83 | URL actual = target.getDiffLink(mockPath); 84 | 85 | assertThat(actual, nullValue()); 86 | } 87 | 88 | @Test 89 | public void testGetDiffLink_NoDst() throws IOException { 90 | Path mockPath = mock(Path.class); 91 | when(mockPath.getDst()).thenReturn(null); 92 | 93 | URL actual = target.getDiffLink(mockPath); 94 | 95 | assertThat(actual, nullValue()); 96 | } 97 | 98 | @Test 99 | public void testGetDiffLink_NoParentCommit() throws IOException { 100 | Path mockPath = mock(Path.class); 101 | GitChangeSet mockGitChangeSet = mock(GitChangeSet.class); 102 | when(mockPath.getChangeSet()).thenReturn(mockGitChangeSet); 103 | when(mockGitChangeSet.getParentCommit()).thenReturn(null); 104 | 105 | URL actual = target.getDiffLink(mockPath); 106 | 107 | assertThat(actual, nullValue()); 108 | } 109 | 110 | @Test 111 | public void testGetDiffLink() throws IOException { 112 | List affectedPaths = Arrays.asList( 113 | "src/main/java/org/jenkinsci/plugins/gitbucket/GitBrowser.java", 114 | "pom.xml", 115 | "README.md"); 116 | String id = "1"; 117 | 118 | Path mockPath = mock(Path.class); 119 | when(mockPath.getEditType()).thenReturn(EditType.EDIT); 120 | when(mockPath.getSrc()).thenReturn("pom.xml"); 121 | when(mockPath.getDst()).thenReturn("pom.xml"); 122 | when(mockPath.getPath()).thenReturn("pom.xml"); 123 | 124 | GitChangeSet mockGitChangeSet = mock(GitChangeSet.class); 125 | when(mockPath.getChangeSet()).thenReturn(mockGitChangeSet); 126 | when(mockGitChangeSet.getAffectedPaths()).thenReturn(affectedPaths); 127 | when(mockGitChangeSet.getId()).thenReturn(id); 128 | when(mockGitChangeSet.getParentCommit()).thenReturn("parent"); 129 | 130 | URL actual = target.getDiffLink(mockPath); 131 | 132 | assertThat(actual.toString(), is(GITBUCKET_URL + "commit/1#diff-1")); 133 | } 134 | 135 | @Test 136 | public void testGetFileLink_NotDelete() throws IOException { 137 | String id = "1"; 138 | 139 | Path mockPath = mock(Path.class); 140 | when(mockPath.getEditType()).thenReturn(EditType.ADD); 141 | when(mockPath.getPath()).thenReturn("pom.xml"); 142 | 143 | GitChangeSet mockGitChangeSet = mock(GitChangeSet.class); 144 | when(mockPath.getChangeSet()).thenReturn(mockGitChangeSet); 145 | when(mockGitChangeSet.getId()).thenReturn(id); 146 | 147 | URL actual = target.getFileLink(mockPath); 148 | 149 | assertThat(actual.toString(), is(GITBUCKET_URL + "blob/" + id + "/pom.xml")); 150 | } 151 | 152 | @Test 153 | public void testGetFileLink_Delete() throws IOException { 154 | List affectedPaths = Arrays.asList( 155 | "src/main/java/org/jenkinsci/plugins/gitbucket/GitBrowser.java", 156 | "pom.xml", 157 | "README.md"); 158 | String id = "1"; 159 | 160 | Path mockPath = mock(Path.class); 161 | when(mockPath.getEditType()).thenReturn(EditType.DELETE); 162 | when(mockPath.getPath()).thenReturn("pom.xml"); 163 | 164 | GitChangeSet mockGitChangeSet = mock(GitChangeSet.class); 165 | when(mockPath.getChangeSet()).thenReturn(mockGitChangeSet); 166 | when(mockGitChangeSet.getAffectedPaths()).thenReturn(affectedPaths); 167 | when(mockGitChangeSet.getId()).thenReturn(id); 168 | 169 | URL actual = target.getFileLink(mockPath); 170 | 171 | assertThat(actual.toString(), is(GITBUCKET_URL + "commit/1#diff-1")); 172 | 173 | } 174 | } -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/gitbucket/GitBucketLinkAnnotatorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, Seiji Sogabe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import hudson.MarkupText; 27 | import hudson.model.FreeStyleBuild; 28 | import hudson.model.FreeStyleProject; 29 | import org.junit.Test; 30 | 31 | import static org.junit.Assert.assertEquals; 32 | import static org.mockito.Matchers.anyString; 33 | import static org.mockito.Matchers.eq; 34 | import static org.mockito.Mockito.mock; 35 | import static org.mockito.Mockito.never; 36 | import static org.mockito.Mockito.spy; 37 | import static org.mockito.Mockito.times; 38 | import static org.mockito.Mockito.verify; 39 | import static org.mockito.Mockito.when; 40 | 41 | public class GitBucketLinkAnnotatorTest { 42 | 43 | private static final String GITBUCKET_URL = "http://bacons.ddo.jp/gitbucket/jenkins/gitbucket-plugin/"; 44 | 45 | @Test 46 | public void testAnnoate() { 47 | FreeStyleProject job = mock(FreeStyleProject.class); 48 | FreeStyleBuild build = mock(FreeStyleBuild.class); 49 | GitBucketProjectProperty gpp = new GitBucketProjectProperty(GITBUCKET_URL, true); 50 | when(build.getProject()).thenReturn(job); 51 | when(job.getProperty(GitBucketProjectProperty.class)).thenReturn(gpp); 52 | 53 | MarkupText text = mock(MarkupText.class); 54 | 55 | GitBucketLinkAnnotator target = spy(new GitBucketLinkAnnotator()); 56 | target.annotate(build, null, text); 57 | 58 | verify(target, times(1)).annotate(text, GITBUCKET_URL); 59 | } 60 | 61 | @Test 62 | public void testAnnoate_NoProjectProperty() { 63 | FreeStyleProject job = mock(FreeStyleProject.class); 64 | FreeStyleBuild build = mock(FreeStyleBuild.class); 65 | GitBucketProjectProperty gpp = null; 66 | when(build.getProject()).thenReturn(job); 67 | when(job.getProperty(GitBucketProjectProperty.class)).thenReturn(gpp); 68 | 69 | MarkupText text = mock(MarkupText.class); 70 | 71 | GitBucketLinkAnnotator target = spy(new GitBucketLinkAnnotator()); 72 | target.annotate(build, null, text); 73 | 74 | verify(target, never()).annotate(eq(text), anyString()); 75 | } 76 | 77 | @Test 78 | public void testAnnoate_LinkDisabled() { 79 | FreeStyleProject job = mock(FreeStyleProject.class); 80 | FreeStyleBuild build = mock(FreeStyleBuild.class); 81 | GitBucketProjectProperty gpp = new GitBucketProjectProperty(GITBUCKET_URL, false); 82 | when(build.getProject()).thenReturn(job); 83 | when(job.getProperty(GitBucketProjectProperty.class)).thenReturn(gpp); 84 | 85 | MarkupText text = mock(MarkupText.class); 86 | 87 | GitBucketLinkAnnotator target = spy(new GitBucketLinkAnnotator()); 88 | target.annotate(build, null, text); 89 | 90 | verify(target, never()).annotate(eq(text), anyString()); 91 | } 92 | 93 | @Test 94 | public void testAnnotateIssueMarkupText() { 95 | assertAnnotatedTextEquals( 96 | "(Close #1) Fixed XSS.", 97 | "(Close #1) Fixed XSS."); 98 | assertAnnotatedTextEquals( 99 | "(close #1) Fixed XSS.", 100 | "(close #1) Fixed XSS."); 101 | assertAnnotatedTextEquals( 102 | "(closes #1) Fixed XSS.", 103 | "(closes #1) Fixed XSS."); 104 | assertAnnotatedTextEquals( 105 | "(closed #1) Fixed XSS.", 106 | "(closed #1) Fixed XSS."); 107 | assertAnnotatedTextEquals( 108 | "(fix #1) Fixed XSS.", 109 | "(fix #1) Fixed XSS."); 110 | assertAnnotatedTextEquals( 111 | "(fixes #1) Fixed XSS.", 112 | "(fixes #1) Fixed XSS."); 113 | assertAnnotatedTextEquals( 114 | "(fixed #1) Fixed XSS.", 115 | "(fixed #1) Fixed XSS."); 116 | assertAnnotatedTextEquals( 117 | "(resolve #1) Fixed XSS.", 118 | "(resolve #1) Fixed XSS."); 119 | assertAnnotatedTextEquals( 120 | "(resolves #1) Fixed XSS.", 121 | "(resolves #1) Fixed XSS."); 122 | assertAnnotatedTextEquals( 123 | "(resolved #1) Fixed XSS.", 124 | "(resolved #1) Fixed XSS."); 125 | assertAnnotatedTextEquals( 126 | "(refs #1) Fixed XSS.", 127 | "(refs #1) Fixed XSS."); 128 | assertAnnotatedTextEquals( 129 | "(refs 1) Fixed XSS.", 130 | "(refs 1) Fixed XSS."); 131 | assertAnnotatedTextEquals( 132 | "(issue #100) Fixed XSS.", 133 | "(issue #100) Fixed XSS."); 134 | assertAnnotatedTextEquals( 135 | "(issue 100) Fixed XSS.", 136 | "(issue 100) Fixed XSS."); 137 | assertAnnotatedTextEquals( 138 | "(Close #1) (Fixed #3) Fixed XSS.", 139 | "(Close #1) " 140 | + "(Fixed #3) Fixed XSS."); 141 | } 142 | 143 | @Test 144 | public void testAnnotatePullsMarkupText() { 145 | assertAnnotatedTextEquals( 146 | "pull #1 Fixed typo.", 147 | "pull #1 Fixed typo."); 148 | assertAnnotatedTextEquals( 149 | "pull 100 Fixed typo.", 150 | "pull 100 Fixed typo."); 151 | } 152 | 153 | @Test 154 | public void testAnnotateWikiMarkupText() { 155 | assertAnnotatedTextEquals( 156 | "wiki maven", 157 | "wiki maven"); 158 | assertAnnotatedTextEquals( 159 | "wiki GitBucket is a Github clone.", 160 | "wiki GitBucket is a Github clone."); 161 | } 162 | 163 | private void assertAnnotatedTextEquals(String originalText, String expectedAnnotatedText) { 164 | MarkupText markupText = new MarkupText(originalText); 165 | GitBucketLinkAnnotator annotator = new GitBucketLinkAnnotator(); 166 | annotator.annotate(markupText, GITBUCKET_URL); 167 | assertEquals(expectedAnnotatedText, markupText.toString(false)); 168 | } 169 | } -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/gitbucket/GitBucketProjectPropertyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, Seiji Sogabe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import hudson.matrix.MatrixBuild; 27 | import hudson.matrix.MatrixConfiguration; 28 | import hudson.matrix.MatrixProject; 29 | import hudson.matrix.MatrixRun; 30 | import hudson.model.AbstractBuild; 31 | import hudson.model.AbstractProject; 32 | import hudson.model.Action; 33 | import hudson.model.FreeStyleBuild; 34 | import hudson.model.FreeStyleProject; 35 | import java.util.Collection; 36 | import java.util.Iterator; 37 | import static org.hamcrest.CoreMatchers.*; 38 | import static org.junit.Assert.assertThat; 39 | import org.junit.Test; 40 | import static org.mockito.Mockito.mock; 41 | import static org.mockito.Mockito.when; 42 | 43 | /** 44 | * Test for {@link GitBucketProjectProperty} class. 45 | * 46 | * @author sogabe 47 | */ 48 | public class GitBucketProjectPropertyTest { 49 | 50 | private static final String GITBUCKET_URL = "http://localhost/gitbucket/sogabe/gitbucket-plugin"; 51 | 52 | private GitBucketProjectProperty target; 53 | 54 | @Test 55 | public void testNormalizeUrl_NotEndWithSlash() { 56 | // not end with slash 57 | target = new GitBucketProjectProperty(GITBUCKET_URL, true); 58 | 59 | String actual = target.getUrl(); 60 | 61 | assertThat(actual, is(GITBUCKET_URL)); 62 | } 63 | 64 | @Test 65 | public void testNormalizeUrl_EndWithSlash() { 66 | // end with slash 67 | String url = GITBUCKET_URL + '/'; 68 | target = new GitBucketProjectProperty(url, true); 69 | 70 | String actual = target.getUrl(); 71 | 72 | assertThat(actual, is(GITBUCKET_URL)); 73 | } 74 | 75 | @Test 76 | public void testNormalizeUrl_EndWithSpace() { 77 | // end with " " 78 | String url = GITBUCKET_URL + ' '; 79 | target = new GitBucketProjectProperty(url, true); 80 | 81 | String actual = target.getUrl(); 82 | 83 | assertThat(actual, is(url.trim())); 84 | } 85 | 86 | @Test 87 | public void testNormalizeUrl_Empty() { 88 | // empty url 89 | String url = " "; 90 | target = new GitBucketProjectProperty(url, true); 91 | 92 | String actual = target.getUrl(); 93 | 94 | assertThat(actual, nullValue()); 95 | } 96 | 97 | @Test 98 | public void testNormalizeUrl_Null() { 99 | // null 100 | String url = null; 101 | target = new GitBucketProjectProperty(url, true); 102 | 103 | String actual = target.getUrl(); 104 | 105 | assertThat(actual, nullValue()); 106 | } 107 | 108 | @Test 109 | public void testGetJobActions_UrlNotSet() { 110 | AbstractProject job = mock(AbstractProject.class); 111 | String url = null; 112 | target = new GitBucketProjectProperty(url, true); 113 | 114 | Collection actual = target.getJobActions(job); 115 | 116 | assertThat(actual, notNullValue()); 117 | assertThat(actual.isEmpty(), is(true)); 118 | } 119 | 120 | @Test 121 | public void testGetJobActions_UrlSet() { 122 | AbstractProject job = mock(AbstractProject.class); 123 | target = new GitBucketProjectProperty(GITBUCKET_URL, true); 124 | 125 | Collection actual = target.getJobActions(job); 126 | 127 | assertThat(actual, notNullValue()); 128 | assertThat(actual.size(), is(1)); 129 | 130 | Iterator it = actual.iterator(); 131 | Action action = it.next(); 132 | assertThat(action, instanceOf(GitBucketLinkAction.class)); 133 | 134 | GitBucketLinkAction linkAction = (GitBucketLinkAction) action; 135 | assertThat(linkAction.getUrlName(), is(GITBUCKET_URL)); 136 | } 137 | 138 | @Test 139 | public void testGet_BuildNull() { 140 | AbstractBuild build = null; 141 | 142 | GitBucketProjectProperty actual = GitBucketProjectProperty.get(build); 143 | 144 | assertThat(actual, nullValue()); 145 | } 146 | 147 | @Test 148 | public void testGet_FreeStyleProject() { 149 | FreeStyleProject job = mock(FreeStyleProject.class); 150 | FreeStyleBuild build = mock(FreeStyleBuild.class); 151 | GitBucketProjectProperty gpp = new GitBucketProjectProperty(GITBUCKET_URL, true); 152 | 153 | when(build.getProject()).thenReturn(job); 154 | when(job.getProperty(GitBucketProjectProperty.class)).thenReturn(gpp); 155 | 156 | GitBucketProjectProperty actual = GitBucketProjectProperty.get(build); 157 | 158 | assertThat(actual, notNullValue()); 159 | assertThat(actual, sameInstance(gpp)); 160 | } 161 | 162 | @Test 163 | public void testGet_MatrixBuild() { 164 | MatrixProject job = mock(MatrixProject.class); 165 | MatrixBuild build = mock(MatrixBuild.class); 166 | GitBucketProjectProperty gpp = new GitBucketProjectProperty(GITBUCKET_URL, true); 167 | 168 | when(build.getProject()).thenReturn(job); 169 | when(job.getProperty(GitBucketProjectProperty.class)).thenReturn(gpp); 170 | 171 | GitBucketProjectProperty actual = GitBucketProjectProperty.get(build); 172 | 173 | assertThat(actual, notNullValue()); 174 | assertThat(actual, sameInstance(gpp)); 175 | } 176 | 177 | @Test 178 | public void testGet_MatrixRun() { 179 | MatrixProject job = mock(MatrixProject.class); 180 | MatrixConfiguration mc = mock(MatrixConfiguration.class); 181 | MatrixRun build = mock(MatrixRun.class); 182 | GitBucketProjectProperty gpp = new GitBucketProjectProperty(GITBUCKET_URL, true); 183 | 184 | when(build.getProject()).thenReturn(mc); 185 | when(mc.getParent()).thenReturn(job); 186 | when(job.getProperty(GitBucketProjectProperty.class)).thenReturn(gpp); 187 | 188 | GitBucketProjectProperty actual = GitBucketProjectProperty.get(build); 189 | 190 | assertThat(actual, notNullValue()); 191 | assertThat(actual, sameInstance(gpp)); 192 | } 193 | 194 | } -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/gitbucket/GitBucketPushRequestTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2013 Seiji Sogabe. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.gitbucket; 26 | 27 | import java.io.InputStream; 28 | import java.util.logging.Level; 29 | import java.util.logging.Logger; 30 | import net.sf.json.JSONObject; 31 | import org.apache.commons.io.IOUtils; 32 | import static org.hamcrest.CoreMatchers.is; 33 | import static org.hamcrest.CoreMatchers.notNullValue; 34 | import org.jenkinsci.plugins.gitbucket.GitBucketPushRequest.User; 35 | import static org.junit.Assert.assertThat; 36 | import org.junit.BeforeClass; 37 | import org.junit.Test; 38 | 39 | /** 40 | * 41 | * @author sogabe 42 | */ 43 | public class GitBucketPushRequestTest { 44 | 45 | private static String json; 46 | 47 | @BeforeClass 48 | public static void setUpClass() throws Exception { 49 | InputStream is = null; 50 | try { 51 | is = GitBucketPushRequestTest.class.getClassLoader().getResourceAsStream("org/jenkinsci/plugins/gitbucket/WebHookPayload.json"); 52 | json = IOUtils.toString(is, "UTF-8"); 53 | LOGGER.log(Level.INFO, "payload: {0}", json); 54 | } finally { 55 | IOUtils.closeQuietly(is); 56 | } 57 | } 58 | 59 | @Test(expected = IllegalArgumentException.class) 60 | public void testCreate_String_Null() { 61 | GitBucketPushRequest.create((String) null); 62 | } 63 | 64 | @Test() 65 | public void testCreate_String() { 66 | GitBucketPushRequest req = GitBucketPushRequest.create(json); 67 | assertThat(req, notNullValue()); 68 | 69 | User pusher = req.getPusher(); 70 | assertThat(pusher, notNullValue()); 71 | assertThat(pusher.getName(), is("sogabe")); 72 | assertThat(pusher.getEmail(), is("sogabe@xxx.ddo.jp")); 73 | } 74 | 75 | @Test(expected = IllegalArgumentException.class) 76 | public void testCreate_JSONObject_Null() { 77 | GitBucketPushRequest.create((JSONObject) null); 78 | } 79 | 80 | @Test(expected = IllegalArgumentException.class) 81 | public void testCreate_JSONObject_NullObject() { 82 | GitBucketPushRequest.create(new JSONObject(true)); 83 | } 84 | 85 | private static final Logger LOGGER = Logger.getLogger(GitBucketPushRequestTest.class.getName()); 86 | } 87 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/gitbucket/GitBucketWebHookCompatibleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2015, Seiji Sogabe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import hudson.model.FreeStyleProject; 27 | import hudson.plugins.git.GitSCM; 28 | import hudson.scm.SCM; 29 | import net.sf.json.JSONObject; 30 | import org.junit.Rule; 31 | import org.junit.Test; 32 | import org.jvnet.hudson.test.JenkinsRule; 33 | import org.kohsuke.stapler.StaplerRequest; 34 | 35 | import static org.mockito.Matchers.anyObject; 36 | import static org.mockito.Mockito.mock; 37 | import static org.mockito.Mockito.never; 38 | import static org.mockito.Mockito.times; 39 | import static org.mockito.Mockito.verify; 40 | import static org.mockito.Mockito.when; 41 | 42 | /** 43 | * Test for {@link GitBucketWebHook} class. 44 | * 45 | * @author sogabe 46 | */ 47 | public class GitBucketWebHookCompatibleTest { 48 | 49 | @Rule 50 | public JenkinsRule j = new JenkinsRule(); 51 | 52 | @Test 53 | public void testPushTrigger_GitSCM() throws Exception { 54 | // Repository URL 55 | String repo = j.createTmpDir().getAbsolutePath(); 56 | 57 | // Setup FreeStyle Project 58 | FreeStyleProject fsp = j.createFreeStyleProject("GitSCM Project"); 59 | 60 | // Setup Trigger 61 | GitBucketPushTrigger trigger = mock(GitBucketPushTrigger.class); 62 | fsp.addTrigger(trigger); 63 | 64 | // Setup SCM 65 | SCM scm = new GitSCM(repo); 66 | fsp.setScm(scm); 67 | 68 | // Setup WebHook request 69 | String payload = createPayload(repo, "jenkins"); 70 | StaplerRequest req = mock(StaplerRequest.class); 71 | when(req.getParameter("payload")).thenReturn(payload); 72 | when(req.getHeader("X-Github-Event")).thenReturn("push"); 73 | 74 | // Post WebHook 75 | GitBucketWebHook hook = new GitBucketWebHook(); 76 | hook.doIndex(req); 77 | 78 | verify(trigger, times(1)).onPost((GitBucketPushRequest) anyObject()); 79 | } 80 | 81 | @Test 82 | public void testPushTrigger_GitSCM_NoRepositoryUrl() throws Exception { 83 | // Repository URL 84 | String repo = j.createTmpDir().getAbsolutePath(); 85 | 86 | // Setup FreeStyle Project 87 | FreeStyleProject fsp = j.createFreeStyleProject("GitSCM Project"); 88 | 89 | // Setup Trigger 90 | GitBucketPushTrigger trigger = mock(GitBucketPushTrigger.class); 91 | fsp.addTrigger(trigger); 92 | 93 | // Setup SCM 94 | SCM scm = new GitSCM(repo); 95 | fsp.setScm(scm); 96 | 97 | // Setup WebHook request 98 | String payload = createPayload(null, "jenkins"); 99 | StaplerRequest req = mock(StaplerRequest.class); 100 | when(req.getParameter("payload")).thenReturn(payload); 101 | 102 | // Post WebHook 103 | GitBucketWebHook hook = new GitBucketWebHook(); 104 | hook.doIndex(req); 105 | 106 | verify(trigger, never()).onPost((GitBucketPushRequest) anyObject()); 107 | } 108 | 109 | @Test 110 | public void testPushTrigger_NoMatchRepo() throws Exception { 111 | // Repository URL 112 | String repo = j.createTmpDir().getAbsolutePath(); 113 | 114 | // Setup FreeStyle Project 115 | FreeStyleProject fsp = j.createFreeStyleProject("GitSCM Project"); 116 | 117 | // Setup Trigger 118 | GitBucketPushTrigger trigger = mock(GitBucketPushTrigger.class); 119 | fsp.addTrigger(trigger); 120 | 121 | // Setup SCM 122 | SCM scm = new GitSCM(repo); 123 | fsp.setScm(scm); 124 | 125 | // Setup WebHook request 126 | String payload = createPayload("No Match Repository", "jenkins"); 127 | StaplerRequest req = mock(StaplerRequest.class); 128 | when(req.getParameter("payload")).thenReturn(payload); 129 | 130 | // Post WebHook 131 | GitBucketWebHook hook = new GitBucketWebHook(); 132 | hook.doIndex(req); 133 | 134 | // make sure that onPost() never called. 135 | verify(trigger, never()).onPost((GitBucketPushRequest) anyObject()); 136 | } 137 | 138 | /** 139 | * GitBucket 3.0 or before. 140 | * { 141 | * "pusher":{"name":"jenkins",#email":"jenkins@jenkins-ci.org"}, 142 | * "repojitory":{"url": "http://git.jenkins-ci.org/jenkins.git"} } 143 | */ 144 | private String createPayload(String url, String pusherName) { 145 | JSONObject json = new JSONObject(); 146 | 147 | JSONObject repository = new JSONObject(); 148 | repository.put("url", url); 149 | json.put("repository", repository); 150 | 151 | JSONObject pusher = new JSONObject(); 152 | pusher.put("name", pusherName); 153 | pusher.put("email", pusherName + "@jenkins-ci.org"); 154 | json.put("pusher", pusher); 155 | 156 | return json.toString(); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/gitbucket/GitBucketWebHookCrumbExclusionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2013 Seiji Sogabe. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import java.io.IOException; 27 | import javax.servlet.FilterChain; 28 | import javax.servlet.ServletException; 29 | import javax.servlet.http.HttpServletRequest; 30 | import javax.servlet.http.HttpServletResponse; 31 | import static org.hamcrest.Matchers.is; 32 | import org.junit.Test; 33 | import static org.junit.Assert.assertThat; 34 | import org.junit.Before; 35 | import static org.mockito.Mockito.mock; 36 | import static org.mockito.Mockito.verify; 37 | import static org.mockito.Mockito.when; 38 | import static org.mockito.Mockito.times; 39 | import static org.mockito.Mockito.doThrow; 40 | 41 | /** 42 | * Unit Test for {@link GitBucketWebHook.GitBucketWebHookCrumbExclusin} 43 | * 44 | * @author Seiji Sogabe 45 | */ 46 | public class GitBucketWebHookCrumbExclusionTest { 47 | 48 | private GitBucketWebHook.GitBucketWebHookCrumbExclusion target; 49 | 50 | @Before 51 | public void setUp() throws Exception { 52 | target = new GitBucketWebHook.GitBucketWebHookCrumbExclusion(); 53 | } 54 | 55 | @Test 56 | public void testProcessPathInfoNull() throws IOException, ServletException { 57 | String pathInfo = null; 58 | HttpServletRequest req = mock(HttpServletRequest.class); 59 | HttpServletResponse res = mock(HttpServletResponse.class); 60 | FilterChain chain = mock(FilterChain.class); 61 | 62 | when(req.getPathInfo()).thenReturn(pathInfo); 63 | 64 | boolean actual = target.process(req, res, chain); 65 | 66 | assertThat(actual, is(false)); 67 | } 68 | 69 | @Test 70 | public void testProcessWrongPathInfo() throws IOException, ServletException { 71 | String pathInfo = "/gitbucket-wrongwebhook/"; 72 | HttpServletRequest req = mock(HttpServletRequest.class); 73 | HttpServletResponse res = mock(HttpServletResponse.class); 74 | FilterChain chain = mock(FilterChain.class); 75 | 76 | when(req.getPathInfo()).thenReturn(pathInfo); 77 | 78 | boolean actual = target.process(req, res, chain); 79 | 80 | assertThat(actual, is(false)); 81 | } 82 | 83 | @Test 84 | public void testProcessPathInfo() throws IOException, ServletException { 85 | String pathInfo = '/' + GitBucketWebHook.WEBHOOK_URL + '/'; 86 | HttpServletRequest req = mock(HttpServletRequest.class); 87 | HttpServletResponse res = mock(HttpServletResponse.class); 88 | FilterChain chain = mock(FilterChain.class); 89 | 90 | when(req.getPathInfo()).thenReturn(pathInfo); 91 | 92 | boolean actual = target.process(req, res, chain); 93 | 94 | assertThat(actual, is(true)); 95 | verify(chain, times(1)).doFilter(req, res); 96 | } 97 | 98 | @Test(expected = IOException.class) 99 | public void testProcessThorowIOException() throws IOException, ServletException { 100 | String pathInfo = '/' + GitBucketWebHook.WEBHOOK_URL + '/'; 101 | HttpServletRequest req = mock(HttpServletRequest.class); 102 | HttpServletResponse res = mock(HttpServletResponse.class); 103 | FilterChain chain = mock(FilterChain.class); 104 | 105 | when(req.getPathInfo()).thenReturn(pathInfo); 106 | doThrow(new IOException()).when(chain).doFilter(req, res); 107 | 108 | target.process(req, res, chain); 109 | } 110 | 111 | @Test(expected = ServletException.class) 112 | public void testProcessThorowServletException() throws IOException, ServletException { 113 | String pathInfo = '/' + GitBucketWebHook.WEBHOOK_URL + '/'; 114 | HttpServletRequest req = mock(HttpServletRequest.class); 115 | HttpServletResponse res = mock(HttpServletResponse.class); 116 | FilterChain chain = mock(FilterChain.class); 117 | 118 | when(req.getPathInfo()).thenReturn(pathInfo); 119 | doThrow(new ServletException()).when(chain).doFilter(req, res); 120 | 121 | target.process(req, res, chain); 122 | } 123 | 124 | 125 | } 126 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/gitbucket/GitBucketWebHookTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013, Seiji Sogabe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.plugins.gitbucket; 25 | 26 | import hudson.model.FreeStyleProject; 27 | import hudson.plugins.git.GitSCM; 28 | import hudson.scm.NullSCM; 29 | import hudson.scm.SCM; 30 | import java.util.Arrays; 31 | import net.sf.json.JSONObject; 32 | import org.jenkinsci.plugins.multiplescms.MultiSCM; 33 | import org.junit.Rule; 34 | import org.junit.Test; 35 | import org.jvnet.hudson.test.JenkinsRule; 36 | import org.kohsuke.stapler.StaplerRequest; 37 | 38 | import static org.mockito.Matchers.anyObject; 39 | import static org.mockito.Mockito.mock; 40 | import static org.mockito.Mockito.never; 41 | import static org.mockito.Mockito.times; 42 | import static org.mockito.Mockito.verify; 43 | import static org.mockito.Mockito.when; 44 | 45 | /** 46 | * Test for {@link GitBucketWebHook} class. 47 | * 48 | * @author sogabe 49 | */ 50 | public class GitBucketWebHookTest { 51 | 52 | @Rule 53 | public JenkinsRule j = new JenkinsRule(); 54 | 55 | @Test 56 | public void testPushTrigger_GitSCM() throws Exception { 57 | // Repository URL 58 | String repo = j.createTmpDir().getAbsolutePath(); 59 | 60 | // Setup FreeStyle Project 61 | FreeStyleProject fsp = j.createFreeStyleProject("GitSCM Project"); 62 | 63 | // Setup Trigger 64 | GitBucketPushTrigger trigger = mock(GitBucketPushTrigger.class); 65 | fsp.addTrigger(trigger); 66 | 67 | // Setup SCM 68 | SCM scm = new GitSCM(repo); 69 | fsp.setScm(scm); 70 | 71 | // Setup WebHook request 72 | String payload = createPayload(repo, "jenkins"); 73 | StaplerRequest req = mock(StaplerRequest.class); 74 | when(req.getParameter("payload")).thenReturn(payload); 75 | when(req.getHeader("X-Github-Event")).thenReturn("push"); 76 | 77 | // Post WebHook 78 | GitBucketWebHook hook = new GitBucketWebHook(); 79 | hook.doIndex(req); 80 | 81 | verify(trigger, times(1)).onPost((GitBucketPushRequest) anyObject()); 82 | } 83 | 84 | @Test 85 | public void testPushTrigger_NoPushEvent() throws Exception { 86 | // Repository URL 87 | String repo = j.createTmpDir().getAbsolutePath(); 88 | 89 | // Setup FreeStyle Project 90 | FreeStyleProject fsp = j.createFreeStyleProject("GitSCM Project"); 91 | 92 | // Setup Trigger 93 | GitBucketPushTrigger trigger = mock(GitBucketPushTrigger.class); 94 | fsp.addTrigger(trigger); 95 | 96 | // Setup SCM 97 | SCM scm = new GitSCM(repo); 98 | fsp.setScm(scm); 99 | 100 | // Setup WebHook request 101 | String payload = createPayload(repo, "jenkins"); 102 | StaplerRequest req = mock(StaplerRequest.class); 103 | when(req.getParameter("payload")).thenReturn(payload); 104 | when(req.getHeader("X-Github-Event")).thenReturn("comment"); 105 | 106 | // Post WebHook 107 | GitBucketWebHook hook = new GitBucketWebHook(); 108 | hook.doIndex(req); 109 | 110 | verify(trigger, never()).onPost((GitBucketPushRequest) anyObject()); 111 | } 112 | 113 | @Test 114 | public void testPushTrigger_GitSCM_NoRepositoryUrl() throws Exception { 115 | // Repository URL 116 | String repo = j.createTmpDir().getAbsolutePath(); 117 | 118 | // Setup FreeStyle Project 119 | FreeStyleProject fsp = j.createFreeStyleProject("GitSCM Project"); 120 | 121 | // Setup Trigger 122 | GitBucketPushTrigger trigger = mock(GitBucketPushTrigger.class); 123 | fsp.addTrigger(trigger); 124 | 125 | // Setup SCM 126 | SCM scm = new GitSCM(repo); 127 | fsp.setScm(scm); 128 | 129 | // Setup WebHook request 130 | String payload = createPayload(null, "jenkins"); 131 | StaplerRequest req = mock(StaplerRequest.class); 132 | when(req.getParameter("payload")).thenReturn(payload); 133 | 134 | // Post WebHook 135 | GitBucketWebHook hook = new GitBucketWebHook(); 136 | hook.doIndex(req); 137 | 138 | verify(trigger, never()).onPost((GitBucketPushRequest) anyObject()); 139 | } 140 | 141 | /** 142 | * compatibility test. 143 | * 144 | * GitBucket 1.7 or before has not pusher information in WebHook. 145 | */ 146 | @Test 147 | public void testPushTrigger_GitSCM_NoPusher() throws Exception { 148 | // Repository URL 149 | String repo = j.createTmpDir().getAbsolutePath(); 150 | 151 | // Setup FreeStyle Project 152 | FreeStyleProject fsp = j.createFreeStyleProject("GitSCM Project"); 153 | 154 | // Setup Trigger 155 | GitBucketPushTrigger trigger = mock(GitBucketPushTrigger.class); 156 | fsp.addTrigger(trigger); 157 | 158 | // Setup SCM 159 | SCM scm = new GitSCM(repo); 160 | fsp.setScm(scm); 161 | 162 | // Setup WebHook request 163 | String payload = createPayload(repo, null); 164 | StaplerRequest req = mock(StaplerRequest.class); 165 | when(req.getParameter("payload")).thenReturn(payload); 166 | when(req.getHeader("X-Github-Event")).thenReturn("push"); 167 | 168 | // Post WebHook 169 | GitBucketWebHook hook = new GitBucketWebHook(); 170 | hook.doIndex(req); 171 | 172 | verify(trigger, times(1)).onPost((GitBucketPushRequest) anyObject()); 173 | } 174 | 175 | @Test 176 | public void testPushTrigger_NoMatchRepo() throws Exception { 177 | // Repository URL 178 | String repo = j.createTmpDir().getAbsolutePath(); 179 | 180 | // Setup FreeStyle Project 181 | FreeStyleProject fsp = j.createFreeStyleProject("GitSCM Project"); 182 | 183 | // Setup Trigger 184 | GitBucketPushTrigger trigger = mock(GitBucketPushTrigger.class); 185 | fsp.addTrigger(trigger); 186 | 187 | // Setup SCM 188 | SCM scm = new GitSCM(repo); 189 | fsp.setScm(scm); 190 | 191 | // Setup WebHook request 192 | String payload = createPayload("No Match Repository", "jenkins"); 193 | StaplerRequest req = mock(StaplerRequest.class); 194 | when(req.getParameter("payload")).thenReturn(payload); 195 | 196 | // Post WebHook 197 | GitBucketWebHook hook = new GitBucketWebHook(); 198 | hook.doIndex(req); 199 | 200 | // make sure that onPost() never called. 201 | verify(trigger, never()).onPost((GitBucketPushRequest) anyObject()); 202 | } 203 | 204 | @Test 205 | public void testPushTrigger_NoTrigger() throws Exception { 206 | // Repository URL 207 | String repo = j.createTmpDir().getAbsolutePath(); 208 | 209 | // Setup FreeStyle Project 210 | FreeStyleProject fsp = j.createFreeStyleProject("GitSCM Project"); 211 | 212 | // Setup Trigger(No Trigger) 213 | // Setup SCM 214 | SCM scm = new GitSCM(repo); 215 | fsp.setScm(scm); 216 | 217 | // Setup WebHook request 218 | String payload = createPayload(repo, "jenkins"); 219 | StaplerRequest req = mock(StaplerRequest.class); 220 | when(req.getParameter("payload")).thenReturn(payload); 221 | 222 | // Post WebHook 223 | GitBucketWebHook hook = new GitBucketWebHook(); 224 | hook.doIndex(req); 225 | } 226 | 227 | @Test 228 | public void testPushTrigger_NoSCM() throws Exception { 229 | // Repository URL 230 | String repo = j.createTmpDir().getAbsolutePath(); 231 | 232 | // Setup FreeStyle Project 233 | FreeStyleProject fsp = j.createFreeStyleProject("GitSCM Project"); 234 | 235 | // Setup Trigger 236 | GitBucketPushTrigger trigger = mock(GitBucketPushTrigger.class); 237 | fsp.addTrigger(trigger); 238 | 239 | // Setup SCM (No SCM) 240 | // Setup WebHook request 241 | String payload = createPayload(repo, "jenkins"); 242 | StaplerRequest req = mock(StaplerRequest.class); 243 | when(req.getParameter("payload")).thenReturn(payload); 244 | 245 | // Post WebHook 246 | GitBucketWebHook hook = new GitBucketWebHook(); 247 | hook.doIndex(req); 248 | 249 | // make sure that onPost() never called. 250 | verify(trigger, never()).onPost((GitBucketPushRequest) anyObject()); 251 | } 252 | 253 | @Test(expected = IllegalArgumentException.class) 254 | public void testPushTrigger_NoPayload() throws Exception { 255 | // Repository URL 256 | String repo = j.createTmpDir().getAbsolutePath(); 257 | 258 | // Setup FreeStyle Project 259 | FreeStyleProject fsp = j.createFreeStyleProject("NoPayload Project"); 260 | 261 | // Setup Trigger 262 | GitBucketPushTrigger trigger = mock(GitBucketPushTrigger.class); 263 | fsp.addTrigger(trigger); 264 | 265 | // Setup SCM 266 | SCM scm = new GitSCM(repo); 267 | fsp.setScm(scm); 268 | 269 | // Setup WebHook request 270 | String payload = null; 271 | StaplerRequest req = mock(StaplerRequest.class); 272 | when(req.getParameter("payload")).thenReturn(payload); 273 | when(req.getHeader("X-Github-Event")).thenReturn("push"); 274 | 275 | // Post WebHook 276 | GitBucketWebHook hook = new GitBucketWebHook(); 277 | hook.doIndex(req); 278 | } 279 | 280 | @Test 281 | public void testPushTrigger_MultiSCM() throws Exception { 282 | // Repository URL 283 | String repo = j.createTmpDir().getAbsolutePath(); 284 | 285 | // Setup FreeStyle Project 286 | FreeStyleProject fsp = j.createFreeStyleProject("MultiSCM Project"); 287 | 288 | // Setup Trigger 289 | GitBucketPushTrigger trigger = mock(GitBucketPushTrigger.class); 290 | fsp.addTrigger(trigger); 291 | 292 | // Setup SCM 293 | SCM gitSCM = new GitSCM(repo); 294 | SCM nullSCM = new NullSCM(); 295 | MultiSCM multiSCM = new MultiSCM(Arrays.asList(gitSCM, nullSCM)); 296 | fsp.setScm(multiSCM); 297 | 298 | // Setup WebHook request 299 | String payload = createPayload(repo, "jenkins"); 300 | StaplerRequest req = mock(StaplerRequest.class); 301 | when(req.getParameter("payload")).thenReturn(payload); 302 | when(req.getHeader("X-Github-Event")).thenReturn("push"); 303 | 304 | // Post WebHook 305 | GitBucketWebHook hook = new GitBucketWebHook(); 306 | hook.doIndex(req); 307 | 308 | verify(trigger, times(1)).onPost((GitBucketPushRequest) anyObject()); 309 | } 310 | 311 | @Test 312 | public void testPushTrigger_NullSCM() throws Exception { 313 | // Repository URL 314 | String repo = j.createTmpDir().getAbsolutePath(); 315 | 316 | // Setup FreeStyle Project 317 | FreeStyleProject fsp = j.createFreeStyleProject("NullSCM Project"); 318 | 319 | // Setup Trigger 320 | GitBucketPushTrigger trigger = mock(GitBucketPushTrigger.class); 321 | fsp.addTrigger(trigger); 322 | 323 | // Setup SCM 324 | SCM nullSCM = new NullSCM(); 325 | fsp.setScm(nullSCM); 326 | 327 | // Setup WebHook request 328 | String payload = createPayload(repo, "jenkins"); 329 | StaplerRequest req = mock(StaplerRequest.class); 330 | when(req.getParameter("payload")).thenReturn(payload); 331 | 332 | // Post WebHook 333 | GitBucketWebHook hook = new GitBucketWebHook(); 334 | hook.doIndex(req); 335 | 336 | verify(trigger, never()).onPost((GitBucketPushRequest) anyObject()); 337 | } 338 | 339 | /** 340 | * GitBucket 3.1 or later. 341 | * { 342 | * "pusher":{"name":"jenkins",#email":"jenkins@jenkins-ci.org"}, 343 | * "repojitory":{"clone_url": "http://git.jenkins-ci.org/jenkins.git"} } 344 | */ 345 | private String createPayload(String url, String pusherName) { 346 | JSONObject json = new JSONObject(); 347 | 348 | JSONObject repository = new JSONObject(); 349 | repository.put("clone_url", url); 350 | repository.put("url", "hoge"); 351 | json.put("repository", repository); 352 | 353 | JSONObject pusher = new JSONObject(); 354 | pusher.put("name", pusherName); 355 | pusher.put("email", pusherName + "@jenkins-ci.org"); 356 | json.put("pusher", pusher); 357 | 358 | return json.toString(); 359 | } 360 | } 361 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/gitbucket/WebHookPayload.json: -------------------------------------------------------------------------------- 1 | { 2 | "pusher": { 3 | "name": "sogabe", 4 | "email": "sogabe@xxx.ddo.jp" 5 | }, 6 | "ref": "refs/heads/master", 7 | "commits": [ { 8 | "id": "9bffdb326046a8dae96c49f0e75f3d9dd8fd8d0c", 9 | "message": "Import Apache Camel 2.7.6 base SimpleFtp\n", 10 | "timestamp": "Wed Nov 06 09:10:24 JST 2013", 11 | "url": "http://xxx.ddo.jp/gitbucket/sogabe/SimpleFtp/commit/9bffdb326046a8dae96c49f0e75f3d9dd8fd8d0c", 12 | "added": [ 13 | ".gitignore", 14 | "pom.xml", 15 | "src" 16 | ], 17 | "removed": [], 18 | "modified": [], 19 | "author": { 20 | "name": "Seiji Sogabe", 21 | "email": "s.sogabe@xxx.com" 22 | } 23 | }], 24 | "repository": { 25 | "name": "SimpleFtp", 26 | "url": "http://xxx.ddo.jp/gitbucket/sogabe/SimpleFtp", 27 | "clone_url": "http://xxx.ddo.jp/gitbucket/git/sogabe/SimpleFtp.git", 28 | "description": "", 29 | "watchers": 0, 30 | "forks": 0, 31 | "private": false, 32 | "owner": { 33 | "name": "sogabe", 34 | "email": "sogabe@xxx.ddo.jp" 35 | } 36 | } 37 | } --------------------------------------------------------------------------------