Skip to content

Commit

Permalink
BDD
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasbjerre committed Apr 3, 2018
1 parent f6be977 commit fc5306c
Show file tree
Hide file tree
Showing 24 changed files with 1,167 additions and 32 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ Changelog of Generic Webhook Plugin.
## Unreleased
### No issue

**BDD**


[e273e1ee8ba0446](https://github.com/jenkinsci/generic-webhook-trigger-plugin/commit/e273e1ee8ba0446) Tomas Bjerre *2018-04-01 17:54:51*

**Issue template**


[f6be97728349dfa](https://github.com/jenkinsci/generic-webhook-trigger-plugin/commit/f6be97728349dfa) Tomas Bjerre *2018-03-27 20:15:32*

**improve header variable name description**

* Version 1.28 introduced RFC 2616 compatibility making all headers lowercase.
Expand Down
22 changes: 19 additions & 3 deletions ISSUE_TEMPLATE
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
When reporting a bug, please try to provide as much information as possible.

* Plugin version used.
* Your configuration:
* A response of an invocation with `curl`, there are examples in the README.
* Or other detailed information of the configuration.
* Your configuration.
* Variables configured, names, expressions...
* Post content received. It can be found in the job execution log. People using GitHub often forget to set the content type in "Manage webhook" when configuring the webhook at GitHub.
* A `curl` command and its response.
* Expected result and actual result.

You may also have a look at the test cases as they should answer the most common questions:

https://github.com/jenkinsci/generic-webhook-trigger-plugin/tree/master/src/test/resources/org/jenkinsci/plugins/gwt/bdd

If you are fiddling with expressions, you may want to checkout:

* [This JSONPath site](https://jsonpath.curiousconcept.com/)
* [This XPath site](http://www.freeformatter.com/xpath-tester.html)
* [This regexp site](https://jex.im/regulex/)

A Curl command can look something like this:
```
curl -v -H "Content-Type: application/json" -X POST -d '{ "app":{ "name":"GitHub API", "url":"http://developer.github.com/v3/oauth/" }}' http://localhost:8080/jenkins/generic-webhook-trigger/invoke?token=sometoken
```
31 changes: 15 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This is a Jenkins plugin that can:
* From the query parameters
* From the headers

3. Contribute those values as variables to the build
3. Trigger a build with those values contribute as variables

There is an optional feature to trigger jobs only if a supplied regular expression matches the extracted variables. Here is an example, let's say the post content looks like this:
```
Expand All @@ -22,18 +22,16 @@ There is an optional feature to trigger jobs only if a supplied regular expressi
}
```

Then you can have a variable, resolved from post content, named `reference` of type `JSONPath` and with expression like `$.ref` .
Then you can have a variable, resolved from post content, named `reference` of type `JSONPath` and with expression like `$.ref` . The optional filter text can be set to `$reference` and the filter regexp set to [^(refs/heads/develop|refs/heads/feature/.+)$](https://jex.im/regulex/#!embed=false&flags=&re=%5E(refs%2Fheads%2Fdevelop%7Crefs%2Fheads%2Ffeature%2F.%2B)%24) to trigger builds only for develop and feature-branches.

The optional filter text can be set to `$reference` and the filter regexp set to [^(refs/heads/develop|refs/heads/feature/.+)$](https://jex.im/regulex/#!embed=false&flags=&re=%5E(refs%2Fheads%2Fdevelop%7Crefs%2Fheads%2Ffeature%2F.%2B)%24) to trigger builds only for develop and feature-branches.
There are more [examples of use cases here](src/test/resources/org/jenkinsci/plugins/gwt/bdd).

## Use case

This means it can trigger on any webhook, like:
It can trigger on any webhook, like:
* [Bitbucket Cloud](https://confluence.atlassian.com/bitbucket/manage-webhooks-735643732.html)
* [Bitbucket Server](https://confluence.atlassian.com/bitbucketserver/managing-webhooks-in-bitbucket-server-938025878.html)
* [GitHub](https://developer.github.com/webhooks/)
* [GitLab](https://docs.gitlab.com/ce/user/project/integrations/webhooks.html)
* [Gogs](https://gogs.io/docs/features/webhook) and [Gitea](https://gitea.io/)
* [Gogs](https://gogs.io/docs/features/webhook) and [Gitea](https://docs.gitea.io/en-us/webhooks/)
* [Assembla](https://blog.assembla.com/AssemblaBlog/tabid/12618/bid/107614/Assembla-Bigplans-Integration-How-To.aspx)
* And many many more!

Expand All @@ -43,25 +41,19 @@ You may want to report back to the invoking system. [HTTP Request Plugin](https:

If a node is selected, then all leafs in that node will be contributed. If a leaf is selected, then only that leaf will be contributed.

There are websites to help fiddle with the expressions. You may want to checkout:

* [This website](https://jsonpath.curiousconcept.com/) to fiddle with JSONPath.
* [This website](http://www.freeformatter.com/xpath-tester.html) to fiddle with XPath.
* [This website](https://jex.im/regulex/) to fiddle with regexp.
## Trigger only specific job

When using the plugin in several jobs, you will have the same URL trigger all jobs. If you want to trigger only a certain job you can:

* Use the `token`-parameter and have different tokens for different jobs.
* Add some request parameter (or header, or post content) and use the **regexp filter** to trigger only if that parameter has a specific value.
* Use the `token`-parameter have different tokens for different jobs. **Don't combine it with any other authentication!** Using only the token means only jobs with that exact token will be visible for that request. This will increase performance and reduce responses of each invocation.
* Or, add some request parameter (or header, or post content) and use the **regexp filter** to trigger only if that parameter has a specific value.

Available in Jenkins [here](https://wiki.jenkins-ci.org/display/JENKINS/Generic+Webhook+Trigger+Plugin).

## Authentication

There is a special `token` parameter. When supplied, it is used with [BuildAuthorizationToken](http://javadoc.jenkins-ci.org/hudson/model/BuildAuthorizationToken.html) to authenticate.

It might be a good idea to have a different token for each job. Then only that job will be visible for that request. This will increase performance and reduce responses of each invocation.

![Parameter](https://github.com/jenkinsci/generic-webhook-trigger-plugin/blob/master/sandbox/configure-token.png)

The token can be supplied as a:
Expand All @@ -70,8 +62,15 @@ The token can be supplied as a:
* Token header: `curl -vs -H "token: abc123" http://localhost:8080/jenkins/generic-webhook-trigger/invoke 2>&1`
* *Authorization* header of type *Bearer* : `curl -vs -H "Authorization: Bearer abc123" http://localhost:8080/jenkins/generic-webhook-trigger/invoke 2>&1`


## Troubleshooting

If you are fiddling with expressions, you may want to checkout:

* [This JSONPath site](https://jsonpath.curiousconcept.com/)
* [This XPath site](http://www.freeformatter.com/xpath-tester.html)
* [This regexp site](https://jex.im/regulex/)

It's probably easiest to do with curl. Given that you have configured a Jenkins job to trigger on Generic Webhook, here are some examples of how to start the jobs.

```
Expand Down
17 changes: 16 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
Expand Down Expand Up @@ -228,5 +229,19 @@ Changelog of Generic Webhook Plugin.
<version>2.13.0</version>
<scope>test</scope>
</dependency>

<!-- Cucumber -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>2.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>2.4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
8 changes: 5 additions & 3 deletions src/main/java/org/jenkinsci/plugins/gwt/GenericTrigger.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ private void addAllParametersFromParameterizedJob(
}

@VisibleForTesting
boolean isMatching(final String renderedRegexpFilterText, final String regexpFilterExpression) {
public static boolean isMatching(
final String renderedRegexpFilterText, final String regexpFilterExpression) {
final boolean noFilterConfigured =
isNullOrEmpty(renderedRegexpFilterText) || isNullOrEmpty(regexpFilterExpression);
if (noFilterConfigured) {
Expand All @@ -207,7 +208,8 @@ boolean isMatching(final String renderedRegexpFilterText, final String regexpFil
}

@VisibleForTesting
String renderText(String regexpFilterText, final Map<String, String> resolvedVariables) {
public static String renderText(
String regexpFilterText, final Map<String, String> resolvedVariables) {
if (isNullOrEmpty(regexpFilterText)) {
return "";
}
Expand All @@ -227,7 +229,7 @@ String renderText(String regexpFilterText, final Map<String, String> resolvedVar
}

@VisibleForTesting
List<String> getVariablesInResolveOrder(final Set<String> unsorted) {
static List<String> getVariablesInResolveOrder(final Set<String> unsorted) {
final List<String> variables = new ArrayList<>(unsorted);
Collections.sort(
variables,
Expand Down
17 changes: 8 additions & 9 deletions src/test/java/org/jenkinsci/plugins/gwt/GenericTriggerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,17 @@ public class GenericTriggerTest {
private String regexpFilterText = null;
private String regexpFilterExpression = null;
private Map<String, String> resolvedVariables;
private GenericTrigger sut;

@Before
public void before() {
resolvedVariables = newHashMap();
resolvedVariables.put("key1", "resolved1");
resolvedVariables.put("key2", "resolved2");
this.sut = new GenericTrigger(null, null, null, null, null);
}

@Test
public void testThatIsMatchingAcceptsEverythingIfNoFilter() {
final boolean actual = sut.isMatching(regexpFilterText, regexpFilterExpression);
final boolean actual = GenericTrigger.isMatching(regexpFilterText, regexpFilterExpression);

assertThat(actual) //
.isTrue();
Expand All @@ -37,7 +35,7 @@ public void testThatIsMatchingAcceptsEverythingIfNoFilter() {
public void testThatIsMatchingWorksDevelopCorrectUser() {
regexpFilterText = "refs/heads/develop tomabje";
regexpFilterExpression = "^refs/heads/develop ((?!jenkins))";
final boolean actual = sut.isMatching(regexpFilterText, regexpFilterExpression);
final boolean actual = GenericTrigger.isMatching(regexpFilterText, regexpFilterExpression);

assertThat(actual) //
.isTrue();
Expand All @@ -47,7 +45,7 @@ public void testThatIsMatchingWorksDevelopCorrectUser() {
public void testThatIsMatchingWorksDevelopNotCorrectUser() {
regexpFilterText = "refs/heads/develop jenkins";
regexpFilterExpression = "^refs/heads/develop ((?!jenkins))";
final boolean actual = sut.isMatching(regexpFilterText, regexpFilterExpression);
final boolean actual = GenericTrigger.isMatching(regexpFilterText, regexpFilterExpression);

assertThat(actual) //
.isFalse();
Expand All @@ -59,7 +57,8 @@ public void testThatIsMatchingAcceptsIfMatching() {
regexpFilterExpression = "resolved1";

final boolean actual =
sut.isMatching(sut.renderText(regexpFilterText, resolvedVariables), regexpFilterExpression);
GenericTrigger.isMatching(
GenericTrigger.renderText(regexpFilterText, resolvedVariables), regexpFilterExpression);

assertThat(actual) //
.isTrue();
Expand All @@ -73,7 +72,7 @@ public void testThatVariablesAreResolvedWithLongestVariableFirst() {
resolvedVariables.put("key2andthensome", "resolved2andmore");

final String text = "$key1 $key2 $key2andthensome $key2";
final String actual = sut.renderText(text, resolvedVariables);
final String actual = GenericTrigger.renderText(text, resolvedVariables);

assertThat(actual) //
.isEqualTo("resolved1 resolved2only resolved2andmore resolved2only");
Expand All @@ -82,7 +81,7 @@ public void testThatVariablesAreResolvedWithLongestVariableFirst() {
@Test
public void testThatVariablesAreResolvedInOrder() {
final List<String> actual =
sut.getVariablesInResolveOrder(
GenericTrigger.getVariablesInResolveOrder(
newHashSet( //
"var1", //
"var2", //
Expand All @@ -108,7 +107,7 @@ public void testThatIsMatchingRejectsIfNotMatching() {

regexpFilterText = "resolved2";
regexpFilterExpression = "$key1";
final boolean actual = sut.isMatching(regexpFilterText, regexpFilterExpression);
final boolean actual = GenericTrigger.isMatching(regexpFilterText, regexpFilterExpression);

assertThat(actual) //
.isFalse();
Expand Down
107 changes: 107 additions & 0 deletions src/test/java/org/jenkinsci/plugins/gwt/bdd/FeatureState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package org.jenkinsci.plugins.gwt.bdd;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jenkinsci.plugins.gwt.GenericHeaderVariable;
import org.jenkinsci.plugins.gwt.GenericRequestVariable;
import org.jenkinsci.plugins.gwt.GenericVariable;

public class FeatureState {
private Map<String, List<String>> headers = new HashMap<>();
private Map<String, String[]> parameterMap = new HashMap<>();
private String postContent;
private List<GenericVariable> genericVariables = new ArrayList<>();
private List<GenericRequestVariable> genericRequestVariables = new ArrayList<>();
private List<GenericHeaderVariable> genericHeaderVariables = new ArrayList<>();
private String regexpFilterText;
private String regexpFilterExpression;

public Map<String, List<String>> getHeaders() {
return headers;
}

public void setHeaders(final Map<String, List<String>> headers) {
this.headers = headers;
}

public Map<String, String[]> getParameterMap() {
return parameterMap;
}

public void setParameterMap(final Map<String, String[]> parameterMap) {
this.parameterMap = parameterMap;
}

public String getPostContent() {
return postContent;
}

public void setPostContent(final String postContent) {
this.postContent = postContent;
}

public List<GenericVariable> getGenericVariables() {
return genericVariables;
}

public void setGenericVariables(final List<GenericVariable> genericVariables) {
this.genericVariables = genericVariables;
}

public List<GenericRequestVariable> getGenericRequestVariables() {
return genericRequestVariables;
}

public void setGenericRequestVariables(
final List<GenericRequestVariable> genericRequestVariables) {
this.genericRequestVariables = genericRequestVariables;
}

public List<GenericHeaderVariable> getGenericHeaderVariables() {
return genericHeaderVariables;
}

public void setGenericHeaderVariables(final List<GenericHeaderVariable> genericHeaderVariables) {
this.genericHeaderVariables = genericHeaderVariables;
}

public String getRegexpFilterText() {
return regexpFilterText;
}

public void setRegexpFilterText(final String regexpFilterText) {
this.regexpFilterText = regexpFilterText;
}

public String getRegexpFilterExpression() {
return regexpFilterExpression;
}

public void setRegexpFilterExpression(final String regexpFilterExpression) {
this.regexpFilterExpression = regexpFilterExpression;
}

@Override
public String toString() {
return "FeatureState [headers="
+ headers
+ ", parameterMap="
+ parameterMap
+ ", postContent="
+ postContent
+ ", genericVariables="
+ genericVariables
+ ", genericRequestVariables="
+ genericRequestVariables
+ ", genericHeaderVariables="
+ genericHeaderVariables
+ ", regexpFilterText="
+ regexpFilterText
+ ", regexpFilterExpression="
+ regexpFilterExpression
+ "]";
}
}
22 changes: 22 additions & 0 deletions src/test/java/org/jenkinsci/plugins/gwt/bdd/GenericFilterPojo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.jenkinsci.plugins.gwt.bdd;

public class GenericFilterPojo {
private String expression;
private String text;

public String getExpression() {
return expression;
}

public void setExpression(final String expression) {
this.expression = expression;
}

public String getText() {
return text;
}

public void setText(final String text) {
this.text = text;
}
}
Loading

0 comments on commit fc5306c

Please sign in to comment.