├── Jenkinsfile
├── images
└── configure-token.png
├── .gitignore
├── src
├── main
│ ├── resources
│ │ ├── com
│ │ │ └── igalg
│ │ │ │ └── jenkins
│ │ │ │ └── plugins
│ │ │ │ └── mswt
│ │ │ │ └── trigger
│ │ │ │ └── ComputedFolderWebHookTrigger
│ │ │ │ ├── config.jelly
│ │ │ │ ├── help.html
│ │ │ │ └── help-token.html
│ │ └── index.jelly
│ └── java
│ │ └── com
│ │ └── igalg
│ │ └── jenkins
│ │ └── plugins
│ │ └── mswt
│ │ ├── locator
│ │ ├── ComputedFolderLocator.java
│ │ ├── LocatedComputedFolder.java
│ │ ├── JenkinsInstanceComputedFolderLocator.java
│ │ └── ComputedFolderWebHookTriggerLocator.java
│ │ ├── trigger
│ │ ├── ComputedFolderWebHookTriggerResult.java
│ │ └── ComputedFolderWebHookTrigger.java
│ │ └── ComputedFolderWebHookRequestReceiver.java
└── test
│ └── java
│ └── com
│ └── igalg
│ └── jenkins
│ └── plugins
│ └── mswt
│ ├── ComputedFolderWebHookRequestReceiverTest.java
│ └── locator
│ └── ComputedFolderWebHookTriggerLocatorTest.java
├── LICENSE
├── README.md
└── pom.xml
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | #!groovy
2 |
3 | buildPlugin()
4 |
--------------------------------------------------------------------------------
/images/configure-token.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkinsci/multibranch-scan-webhook-trigger-plugin/HEAD/images/configure-token.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.versionsBackup
2 | .factorypath
3 | .classpath
4 | .project
5 | .settings
6 | .okhttpcache
7 | target
8 | work
9 | .idea
10 | *iml
11 | bin
12 |
--------------------------------------------------------------------------------
/src/main/resources/com/igalg/jenkins/plugins/mswt/trigger/ComputedFolderWebHookTrigger/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 igalg
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Multibranch Scan Webhook Trigger
2 |
3 | [](https://ci.jenkins.io/job/Plugins/job/multibranch-scan-webhook-trigger-plugin)
4 |
5 | All multibranch projects comes with build in periodically scan trigger that polls scm and check wich branches has changed and than build those branches.
6 |
7 | This is a Jenkins plugin that add functionality to do this scan on webhook:
8 |
9 | 1. Receive any HTTP request, `JENKINS_URL/multibranch-webhook-trigger/invoke?token=TOKENHERE`
10 | 2. Trigger a multibranch jobs scan that matches the token
11 |
12 |
13 |
14 | ### Configure the Token parameter
15 |
16 | There is a special `token` parameter. When supplied, the invocation will only trigger jobs with that exact token. The token also allows invocations without any other authentication credentials.
17 |
18 | 
19 |
20 | The token can be supplied as a:
21 |
22 | * Request parameter: `curl -POST http://localhost:8080/jenkins/multibranch-webhook-trigger/invoke?token=my-token`
23 | * Token header: `curl -POST -H "token: my-token" http://localhost:8080/jenkins/multibranch-webhook-trigger/invoke`
24 |
25 |
--------------------------------------------------------------------------------
/src/main/resources/index.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 | Trigger that can receive any HTTP request and trigger a multibranch job scan when token matched.
27 |
28 |
--------------------------------------------------------------------------------
/src/main/resources/com/igalg/jenkins/plugins/mswt/trigger/ComputedFolderWebHookTrigger/help.html:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 | Allows Multibranch Scan Webhook Trigger to trigger scan of this multibranch job.
27 |
28 |
--------------------------------------------------------------------------------
/src/main/resources/com/igalg/jenkins/plugins/mswt/trigger/ComputedFolderWebHookTrigger/help-token.html:
--------------------------------------------------------------------------------
1 |
24 |
25 | The token to match with webhook token.
26 | Receive any HTTP request, JENKINS_URL/multibranch-webhook-trigger/invoke?token=[Trigger token]
27 | If a token match, than a multibranch scan will bi triggered.
28 |
--------------------------------------------------------------------------------
/src/main/java/com/igalg/jenkins/plugins/mswt/locator/ComputedFolderLocator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2019 igalg
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 com.igalg.jenkins.plugins.mswt.locator;
25 |
26 | import java.util.List;
27 |
28 | import com.cloudbees.hudson.plugins.folder.computed.ComputedFolder;
29 |
30 | public interface ComputedFolderLocator {
31 | @SuppressWarnings("rawtypes")
32 | public List getAllComputedFolders() ;
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/igalg/jenkins/plugins/mswt/locator/LocatedComputedFolder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2019 igalg
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 com.igalg.jenkins.plugins.mswt.locator;
25 |
26 | import com.igalg.jenkins.plugins.mswt.trigger.ComputedFolderWebHookTrigger;
27 |
28 | public class LocatedComputedFolder {
29 |
30 | private final String fullName;
31 | private final ComputedFolderWebHookTrigger trigger;
32 |
33 | public LocatedComputedFolder(String fullName, ComputedFolderWebHookTrigger trigger) {
34 | this.fullName = fullName;
35 | this.trigger = trigger;
36 | }
37 |
38 | public ComputedFolderWebHookTrigger getTrigger() {
39 | return trigger;
40 | }
41 |
42 | public String getFullName() {
43 | return fullName;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/igalg/jenkins/plugins/mswt/trigger/ComputedFolderWebHookTriggerResult.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2019 igalg
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 com.igalg.jenkins.plugins.mswt.trigger;
25 |
26 | import hudson.model.Queue.Item;
27 |
28 | public class ComputedFolderWebHookTriggerResult {
29 |
30 | private final String url;
31 | private final long id;
32 | private final boolean triggered;
33 |
34 | public ComputedFolderWebHookTriggerResult(Item queueItem) {
35 | if (queueItem != null) {
36 | this.url = queueItem.getUrl();
37 | this.id = queueItem.getId();
38 | this.triggered = true;
39 | } else {
40 | this.url = null;
41 | this.id = 0;
42 | this.triggered = false;
43 | }
44 | }
45 |
46 | public boolean isTriggered() {
47 | return triggered;
48 | }
49 |
50 | public long getId() {
51 | return id;
52 | }
53 |
54 | public String getUrl() {
55 | return url;
56 | }
57 |
58 | }
--------------------------------------------------------------------------------
/src/main/java/com/igalg/jenkins/plugins/mswt/locator/JenkinsInstanceComputedFolderLocator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2019 igalg
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 com.igalg.jenkins.plugins.mswt.locator;
25 |
26 | import java.util.List;
27 |
28 | import org.acegisecurity.context.SecurityContext;
29 | import org.acegisecurity.context.SecurityContextHolder;
30 |
31 | import com.cloudbees.hudson.plugins.folder.computed.ComputedFolder;
32 |
33 | import hudson.security.ACL;
34 | import jenkins.model.Jenkins;
35 |
36 | public class JenkinsInstanceComputedFolderLocator implements ComputedFolderLocator {
37 | @SuppressWarnings({ "rawtypes", "deprecation" })
38 | public List getAllComputedFolders() {
39 |
40 | SecurityContext orig = null;
41 | try {
42 | orig = ACL.impersonate(ACL.SYSTEM);
43 | return Jenkins.getInstance().getAllItems(ComputedFolder.class);
44 | }finally {
45 | SecurityContextHolder.setContext(orig);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/test/java/com/igalg/jenkins/plugins/mswt/ComputedFolderWebHookRequestReceiverTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2019 igalg
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 com.igalg.jenkins.plugins.mswt;
25 |
26 | import static com.google.common.collect.ImmutableMap.of;
27 | import static com.google.common.collect.Lists.newArrayList;
28 | import static com.google.common.collect.Maps.newHashMap;
29 | import static org.assertj.core.api.Assertions.assertThat;
30 |
31 | import java.util.List;
32 | import java.util.Map;
33 |
34 | import org.junit.Before;
35 | import org.junit.Test;
36 |
37 | public class ComputedFolderWebHookRequestReceiverTest {
38 |
39 | ComputedFolderWebHookRequestReceiver computedFolderWebHookRequestReceiver;
40 |
41 | @Before
42 | public void init() {
43 | computedFolderWebHookRequestReceiver = new ComputedFolderWebHookRequestReceiver();
44 | }
45 |
46 | @Test
47 | public void testThatNoTokenReturnsNull() {
48 |
49 | Map> headers = newHashMap();
50 | Map parameterMap = newHashMap();
51 | String token = computedFolderWebHookRequestReceiver.getGivenToken(headers, parameterMap);
52 | assertThat(token).isNull();
53 | }
54 |
55 | @Test
56 | public void testThatParameterTokenReturnsThatToken() {
57 | Map> headers = newHashMap();
58 | Map parameterMap = of("token", new String[] {"token-parameter"});
59 | final String token = computedFolderWebHookRequestReceiver.getGivenToken(headers, parameterMap);
60 | assertThat(token).isEqualTo("token-parameter");
61 | }
62 |
63 | @Test
64 | public void testThatHeaderTokenReturnsThatToken() {
65 | Map> headers = of("token", (List) newArrayList("token-header"));
66 | Map parameterMap = newHashMap();
67 | String token = computedFolderWebHookRequestReceiver.getGivenToken(headers, parameterMap);
68 | assertThat(token).isEqualTo("token-header");
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/igalg/jenkins/plugins/mswt/trigger/ComputedFolderWebHookTrigger.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2019 igalg
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 com.igalg.jenkins.plugins.mswt.trigger;
25 |
26 | import java.util.logging.Logger;
27 |
28 | import org.kohsuke.stapler.DataBoundConstructor;
29 |
30 | import com.cloudbees.hudson.plugins.folder.computed.ComputedFolder;
31 |
32 | import hudson.Extension;
33 | import hudson.model.Item;
34 | import hudson.model.Queue;
35 | import hudson.triggers.Trigger;
36 | import hudson.triggers.TriggerDescriptor;
37 |
38 |
39 | public class ComputedFolderWebHookTrigger extends Trigger> {
40 |
41 | private static final Logger LOGGER = Logger.getLogger(ComputedFolderWebHookTrigger.class.getName());
42 |
43 |
44 |
45 |
46 | private final String token;
47 |
48 |
49 | public String getToken() {
50 | return token;
51 | }
52 |
53 |
54 |
55 | @DataBoundConstructor
56 | public ComputedFolderWebHookTrigger(String token) {
57 | this.token = token;
58 | LOGGER.info("setting token:"+token);
59 |
60 | }
61 |
62 |
63 | public ComputedFolderWebHookTriggerResult trigger() {
64 | if(job == null)
65 | return null;
66 | Queue.Item queueItem = job.scheduleBuild2(0);
67 | return new ComputedFolderWebHookTriggerResult(queueItem);
68 | }
69 |
70 |
71 |
72 |
73 |
74 | /**
75 | * Our {@link hudson.model.Descriptor}
76 | */
77 | @Extension
78 | @SuppressWarnings("unused") // instantiated by Jenkins
79 | public static class DescriptorImpl extends TriggerDescriptor {
80 | /**
81 | * {@inheritDoc}
82 | */
83 | public boolean isApplicable(Item item) {
84 | return item instanceof ComputedFolder;
85 | }
86 |
87 | /**
88 | * {@inheritDoc}
89 | */
90 | public String getDisplayName() {
91 | return "Scan by webhook";
92 | }
93 | }
94 |
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/com/igalg/jenkins/plugins/mswt/locator/ComputedFolderWebHookTriggerLocator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2019 igalg
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 com.igalg.jenkins.plugins.mswt.locator;
25 |
26 | import static java.nio.charset.StandardCharsets.UTF_8;
27 |
28 | import java.security.MessageDigest;
29 | import java.util.ArrayList;
30 | import java.util.List;
31 | import java.util.Map;
32 |
33 | import com.cloudbees.hudson.plugins.folder.computed.ComputedFolder;
34 | import com.igalg.jenkins.plugins.mswt.trigger.ComputedFolderWebHookTrigger;
35 |
36 | import hudson.triggers.Trigger;
37 | import hudson.triggers.TriggerDescriptor;
38 |
39 | public class ComputedFolderWebHookTriggerLocator {
40 | public static List locateJobsWithTrigger(ComputedFolderLocator jobLocator , String givenToken) {
41 | List locatedList = new ArrayList();
42 | @SuppressWarnings("rawtypes")
43 | List candidateProjects = jobLocator.getAllComputedFolders();
44 | for (ComputedFolder> candidateJob : candidateProjects) {
45 | ComputedFolderWebHookTrigger computedFolderWebHookTrigger = findComputedFolderWebHookTrigger(candidateJob.getTriggers());
46 | if (computedFolderWebHookTrigger != null &&
47 | MessageDigest.isEqual(computedFolderWebHookTrigger.getToken().getBytes(UTF_8), givenToken.getBytes(UTF_8))) {
48 | locatedList.add(new LocatedComputedFolder(candidateJob.getFullName(), computedFolderWebHookTrigger));
49 | }
50 |
51 | }
52 | return locatedList;
53 | }
54 |
55 | private static ComputedFolderWebHookTrigger findComputedFolderWebHookTrigger(Map> triggers) {
56 | if (triggers == null) {
57 | return null;
58 | }
59 | for ( Trigger> candidate : triggers.values()) {
60 | if (candidate instanceof ComputedFolderWebHookTrigger) {
61 | return (ComputedFolderWebHookTrigger) candidate;
62 | }
63 | }
64 | return null;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/test/java/com/igalg/jenkins/plugins/mswt/locator/ComputedFolderWebHookTriggerLocatorTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2019 igalg
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 com.igalg.jenkins.plugins.mswt.locator;
25 |
26 | import static org.assertj.core.api.Assertions.assertThat;
27 | import static org.mockito.Mockito.mock;
28 | import static org.mockito.Mockito.when;
29 |
30 | import java.util.ArrayList;
31 | import java.util.HashMap;
32 | import java.util.List;
33 | import java.util.Map;
34 |
35 | import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject;
36 | import org.junit.Before;
37 | import org.junit.Test;
38 | import org.junit.runner.RunWith;
39 | import org.powermock.api.mockito.PowerMockito;
40 | import org.powermock.core.classloader.annotations.PrepareForTest;
41 | import org.powermock.modules.junit4.PowerMockRunner;
42 |
43 | import com.cloudbees.hudson.plugins.folder.computed.ComputedFolder;
44 | import com.igalg.jenkins.plugins.mswt.trigger.ComputedFolderWebHookTrigger;
45 |
46 | import hudson.triggers.Trigger;
47 | import hudson.triggers.TriggerDescriptor;
48 |
49 | @SuppressWarnings("rawtypes")
50 | @RunWith(PowerMockRunner.class)
51 | @PrepareForTest({WorkflowMultiBranchProject.class})
52 | public class ComputedFolderWebHookTriggerLocatorTest {
53 |
54 | private List computedFolderList;
55 | private final WorkflowMultiBranchProject multibranchJobWithNoToken = createJobWorkflowMultiBranchProject("abc");
56 | private final WorkflowMultiBranchProject multibranchJobWithToken = createJobWorkflowMultiBranchProject("token");
57 | private final WorkflowMultiBranchProject multibranchJobWithNoTrigger = createJobWorkflowMultiBranchProjectWithouTrigger();
58 | private ComputedFolderLocator computedFolderLocator;
59 |
60 | @Before
61 | public void before() {
62 | computedFolderList = new ArrayList<>();
63 | computedFolderList.add(multibranchJobWithNoToken);
64 | computedFolderList.add(multibranchJobWithToken);
65 | computedFolderList.add(multibranchJobWithNoTrigger);
66 | computedFolderLocator = new ComputedFolderLocator() {
67 |
68 | @Override
69 | public List getAllComputedFolders(){
70 | return computedFolderList;
71 | }
72 | };
73 | }
74 |
75 | @Test
76 | public void testThatJobsWithMatchedTokenFoundedAndNotMatchNotFounded() {
77 | final String givenToken = "token";
78 |
79 | List jobsToTrigger = getJobNameList(ComputedFolderWebHookTriggerLocator.locateJobsWithTrigger(computedFolderLocator, givenToken));
80 |
81 | assertThat(jobsToTrigger.contains(multibranchJobWithToken.getFullName())).isTrue();
82 | assertThat(jobsToTrigger.contains(multibranchJobWithNoToken.getFullName())).isFalse();
83 | }
84 |
85 | @Test
86 | public void testThatJobsWithoutTriggerAreNotLocated() {
87 | final String givenToken = "token";
88 |
89 | List jobsToTrigger = getJobNameList(ComputedFolderWebHookTriggerLocator.locateJobsWithTrigger(computedFolderLocator, givenToken));
90 |
91 |
92 | assertThat(jobsToTrigger.contains(multibranchJobWithNoTrigger.getFullName())).isFalse();
93 |
94 | }
95 |
96 |
97 | private WorkflowMultiBranchProject createJobWorkflowMultiBranchProjectWithouTrigger() {
98 | WorkflowMultiBranchProject mock = PowerMockito.mock(WorkflowMultiBranchProject.class);
99 | PowerMockito.when(mock.getFullName())
100 | .thenReturn("WorkflowMultiBranchProject_noTrigger");
101 | return mock;
102 | }
103 | private WorkflowMultiBranchProject createJobWorkflowMultiBranchProject(String token) {
104 | WorkflowMultiBranchProject mock = PowerMockito.mock(WorkflowMultiBranchProject.class);
105 | PowerMockito.when(mock.getFullName()).thenReturn("WorkflowMultiBranchProject_" + token);
106 | Map> triggers = new HashMap<>();
107 | TriggerDescriptor typeDescr = mock(TriggerDescriptor.class);
108 | ComputedFolderWebHookTrigger trigger = new ComputedFolderWebHookTrigger(token);
109 | triggers.put(typeDescr, trigger);
110 | when(mock.getTriggers()).thenReturn(triggers);
111 | return mock;
112 | }
113 |
114 |
115 |
116 | private List getJobNameList(List jobsToTrigger) {
117 | List names = new ArrayList<>();
118 | for ( LocatedComputedFolder locatedComputedFolder : jobsToTrigger)
119 | names.add(locatedComputedFolder.getFullName());
120 | return names;
121 | }
122 |
123 |
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/java/com/igalg/jenkins/plugins/mswt/ComputedFolderWebHookRequestReceiver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2019 igalg
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 com.igalg.jenkins.plugins.mswt;
25 |
26 | import static hudson.util.HttpResponses.okJSON;
27 | import static java.util.logging.Level.INFO;
28 | import static java.util.logging.Level.SEVERE;
29 |
30 | import java.io.IOException;
31 | import java.util.Collections;
32 | import java.util.Enumeration;
33 | import java.util.HashMap;
34 | import java.util.List;
35 | import java.util.Map;
36 | import java.util.logging.Logger;
37 |
38 | import javax.servlet.FilterChain;
39 | import javax.servlet.ServletException;
40 | import javax.servlet.http.HttpServletRequest;
41 | import javax.servlet.http.HttpServletResponse;
42 |
43 | import org.kohsuke.stapler.HttpResponse;
44 | import org.kohsuke.stapler.StaplerRequest;
45 |
46 | import com.google.common.annotations.VisibleForTesting;
47 | import com.igalg.jenkins.plugins.mswt.locator.ComputedFolderLocator;
48 | import com.igalg.jenkins.plugins.mswt.locator.ComputedFolderWebHookTriggerLocator;
49 | import com.igalg.jenkins.plugins.mswt.locator.JenkinsInstanceComputedFolderLocator;
50 | import com.igalg.jenkins.plugins.mswt.locator.LocatedComputedFolder;
51 | import com.igalg.jenkins.plugins.mswt.trigger.ComputedFolderWebHookTrigger;
52 | import com.igalg.jenkins.plugins.mswt.trigger.ComputedFolderWebHookTriggerResult;
53 |
54 | import hudson.Extension;
55 | import hudson.model.UnprotectedRootAction;
56 | import hudson.security.csrf.CrumbExclusion;
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | @Extension
65 | public class ComputedFolderWebHookRequestReceiver extends CrumbExclusion implements UnprotectedRootAction {
66 |
67 | private static final String NO_JOBS_MSG = "Did not find any jobs with multibranch scan webhook trigger configured."
68 | + "you need to pass token like ...multibranch-webhook-trigger/invoke?token=TOKENHERE. ";
69 |
70 | private static final String URL_NAME = "multibranch-webhook-trigger";
71 |
72 | private static final String TOKEN_PARAM = "token";
73 |
74 | private static final Logger LOGGER = Logger.getLogger(ComputedFolderWebHookRequestReceiver.class.getName());
75 |
76 |
77 |
78 |
79 |
80 | @Override
81 | public boolean process(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain)throws IOException, ServletException {
82 | final String pathInfo = request.getPathInfo();
83 |
84 | if (pathInfo != null && pathInfo.startsWith("/" + URL_NAME + "/")) {
85 | chain.doFilter(request, response);
86 | return true;
87 | }
88 | return false;
89 | }
90 |
91 | public HttpResponse doInvoke(final StaplerRequest request) {
92 | Map parameterMap = null;
93 | Map> headers = null;
94 |
95 | headers = getHeaders(request);
96 | parameterMap = request.getParameterMap();
97 |
98 | final String givenToken = getGivenToken(headers, parameterMap);
99 | return doInvoke(givenToken);
100 | }
101 |
102 |
103 |
104 | @VisibleForTesting
105 | String getGivenToken(final Map> headers, final Map parameterMap) {
106 | if (parameterMap.containsKey(TOKEN_PARAM)) {
107 | return parameterMap.get(TOKEN_PARAM)[0];
108 | }
109 | if (headers.containsKey(TOKEN_PARAM)) {
110 | return headers.get(TOKEN_PARAM).get(0);
111 | }
112 | return null;
113 | }
114 |
115 | @VisibleForTesting
116 | Map> getHeaders(final StaplerRequest request) {
117 | Map> headers = new HashMap<>();
118 | Enumeration headersEnumeration = request.getHeaderNames();
119 | while (headersEnumeration.hasMoreElements()) {
120 | String headerName = headersEnumeration.nextElement();
121 | headers.put(headerName.toLowerCase(), Collections.list(request.getHeaders(headerName)));
122 | }
123 | return headers;
124 | }
125 |
126 | @VisibleForTesting
127 | HttpResponse doInvoke(final String givenToken) {
128 | ComputedFolderLocator computedFolderLocator = new JenkinsInstanceComputedFolderLocator();
129 | List locatedList = ComputedFolderWebHookTriggerLocator.locateJobsWithTrigger(computedFolderLocator,givenToken);
130 | Map triggerResultsMap = new HashMap();
131 |
132 | if (locatedList.isEmpty()) {
133 | LOGGER.log(INFO, NO_JOBS_MSG);
134 | triggerResultsMap.put("ANY", NO_JOBS_MSG);
135 | }
136 |
137 | for (LocatedComputedFolder locatedComputedFolder : locatedList) {
138 | try {
139 | LOGGER.log(INFO, "Triggering " + locatedComputedFolder.getFullName());
140 | ComputedFolderWebHookTrigger trigger = locatedComputedFolder.getTrigger();
141 | ComputedFolderWebHookTriggerResult triggerResults = trigger.trigger();
142 | triggerResultsMap.put(locatedComputedFolder.getFullName(), triggerResults);
143 | } catch (Throwable t) {
144 | LOGGER.log(SEVERE, locatedComputedFolder.getFullName(), t);
145 | final String msg = "Exception occurred, full stack trace in Jenkins server log. Thrown in: " + t.getStackTrace()[0].getClassName() + ":" + t.getStackTrace()[0].getLineNumber();
146 | triggerResultsMap.put(locatedComputedFolder.getFullName(), msg);
147 | }
148 | }
149 |
150 | Map response = new HashMap<>();
151 | response.put("triggerResults", triggerResultsMap);
152 | return okJSON(response);
153 | }
154 |
155 | @Override
156 | public String getIconFileName() {
157 | return null;
158 | }
159 |
160 | @Override
161 | public String getDisplayName() {
162 | return null;
163 | }
164 |
165 | @Override
166 | public String getUrlName() {
167 | return URL_NAME;
168 | }
169 |
170 |
171 | }
172 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 | org.jenkins-ci.plugins
5 | plugin
6 | 4.18
7 |
8 |
9 |
10 | 8
11 |
12 | false
13 |
14 | 2.263.1
15 | 2.6.4
16 | 4.5.2
17 | true
18 | 1.18
19 |
20 |
21 | igalg.jenkins.plugins
22 | multibranch-scan-webhook-trigger
23 | 1.0.12-SNAPSHOT
24 | Multibranch Scan Webhook Trigger
25 | Trigger that can receive any HTTP request and trigger a multibranch scan.
26 |
27 | https://github.com/jenkinsci/multibranch-scan-webhook-trigger-plugin
28 |
29 | hpi
30 |
31 |
32 |
33 | MIT License
34 | http://opensource.org/licenses/MIT
35 |
36 |
37 |
38 |
39 | igalg
40 | Igal Gluh
41 | igal.gluh@gmail.com
42 |
43 |
44 |
45 |
46 | GitHub
47 | https://github.com/jenkinsci/multibranch-scan-webhook-trigger
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | scm:git:ssh://git@github.com/jenkinsci/multibranch-scan-webhook-trigger.git
56 | scm:git:ssh://git@github.com/jenkinsci/multibranch-scan-webhook-trigger.git
57 | https://github.com/jenkinsci/multibranch-scan-webhook-trigger.git
58 | HEAD
59 |
60 |
61 |
62 |
63 | repo.jenkins-ci.org
64 | https://repo.jenkins-ci.org/public/
65 |
66 |
67 |
68 |
69 |
70 | repo.jenkins-ci.org
71 | https://repo.jenkins-ci.org/public/
72 |
73 |
74 |
75 |
76 |
77 |
78 | maven.jenkins-ci.org
79 | jenkinsci-releases
80 | https://repo.jenkins-ci.org/releases
81 |
82 |
83 | maven.jenkins-ci.org
84 | jenkinsci-snapshots
85 | https://repo.jenkins-ci.org/snapshots
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | org.apache.maven.plugins
95 | maven-surefire-plugin
96 |
97 |
98 | org.apache.maven.plugins
99 | maven-eclipse-plugin
100 |
101 | true
102 | true
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | src/main/resources
111 | true
112 |
113 |
114 |
115 |
116 | src/test/resources
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 | org.kohsuke
125 | access-modifier-annotation
126 |
127 |
128 |
129 | org.jenkins-ci
130 | annotation-indexer
131 |
132 |
133 |
138 |
139 |
140 |
141 |
142 | org.jenkins-ci.plugins
143 | scm-api
144 | ${scm-api.version}
145 |
146 |
147 | org.jenkins-ci.plugins
148 | github-api
149 | 1.116
150 |
151 |
152 | org.jenkins-ci.plugins
153 | git
154 | ${git-plugin.version}
155 |
156 |
157 | org.jenkins-ci.plugins
158 | branch-api
159 | 2.5.9
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 | com.jayway.jsonpath
173 | json-path
174 | 2.4.0
175 |
176 |
177 | com.google.code.gson
178 | gson
179 | 2.8.2
180 |
181 |
182 | org.jenkins-ci.plugins
183 | structs
184 | 1.22
185 |
186 |
187 | org.jenkins-ci.plugins
188 | credentials
189 | 2.3.19
190 |
191 |
192 | org.jenkins-ci.plugins
193 | structs
194 |
195 |
196 |
197 |
198 |
199 |
200 | junit
201 | junit
202 | test
203 |
204 |
205 | org.assertj
206 | assertj-core
207 | 2.1.0
208 | test
209 |
210 |
211 | org.powermock
212 | powermock-module-junit4
213 |
214 | test
215 |
216 |
217 | org.powermock
218 | powermock-api-mockito2
219 |
220 | test
221 |
222 |
223 |
224 |
225 |
226 | org.jenkins-ci.plugins.workflow
227 | workflow-job
228 | 2.41
229 | test
230 |
231 |
232 | org.jenkins-ci.plugins.workflow
233 | workflow-cps
234 | 2.92
235 | test
236 |
237 |
238 |
239 |
240 |
241 | org.jenkins-ci.plugins.workflow
242 | workflow-step-api
243 | 2.23
244 | test
245 |
246 |
247 | org.jenkins-ci.plugins
248 | token-macro
249 | 2.13
250 | test
251 |
252 |
253 | org.jenkins-ci.plugins
254 | plain-credentials
255 | 1.4
256 | test
257 |
258 |
259 | org.jenkins-ci.plugins
260 | script-security
261 | 1.77
262 | test
263 |
264 |
265 |
266 | org.jenkins-ci.plugins.workflow
267 | workflow-scm-step
268 | 2.13
269 | test
270 |
271 |
272 | org.jenkins-ci.plugins.workflow
273 | workflow-aggregator
274 | 2.6
275 | test
276 |
277 |
278 | org.jenkins-ci.plugins
279 | github-branch-source
280 | 2.9.0
281 | test
282 |
283 |
284 | org.jenkins-ci.plugins
285 | matrix-project
286 | 1.18
287 | test
288 |
289 |
290 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
--------------------------------------------------------------------------------