Skip to content

Commit

Permalink
Merge pull request #56 from jdavisp3/continue-processing
Browse files Browse the repository at this point in the history
Add processAllRules option.
  • Loading branch information
ashwanthkumar committed Oct 17, 2016
2 parents f7d2752 + 0bbc459 commit 0deb3cf
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 56 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ gocd.slack {
slackDisplayName = "gocd-slack-bot"
slackUserIconURL = "http://example.com/slack-bot.png"
displayMaterialChanges = true
process-all-rules = true
proxy {
hostname = "localhost"
port = "5555"
Expand All @@ -40,6 +41,7 @@ gocd.slack {
- `webhookUrl` - Slack Webhook URL
- `channel` - Override the default channel where we should send the notifications in slack. You can also give a value starting with `@` to send it to any specific user.
- `displayMaterialChanges` - Display material changes in the notification (git revisions for example). Defaults to true, set to false if you want to hide.
- `process-all-rules` - If true, all matching rules are applied instead of just the first.
- `proxy` - Specify proxy related settings for the plugin.
- `proxy.hostname` - Proxy Host
- `proxy.port` - Proxy Port
Expand Down Expand Up @@ -67,7 +69,7 @@ gocd.slack {
}]
}
```
`gocd.slack.pipelines` contains all the rules for the go-server. It is a list of rules (see below for what the parameters mean) for various pipelines. The plugin will pick the first matching pipeline rule from the pipelines collection above, so your most specific rule should be first, with the most generic rule at the bottom.
`gocd.slack.pipelines` contains all the rules for the go-server. It is a list of rules (see below for what the parameters mean) for various pipelines. The plugin will pick the first matching pipeline rule from the pipelines collection above, so your most specific rule should be first, with the most generic rule at the bottom. Alternatively, set the `process-all-rules` option to `true` and all matching rules will be applied.
- `name` - Regex to match the pipeline name
- `stage` - Regex to match the stage name
- `state` - State of the pipeline at which we should send a notification. You can provide multiple values separated by pipe (`|`) symbol. Valid values are passed, failed, cancelled, building, fixed, broken or all.
Expand Down
4 changes: 3 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ gocd.slack {
slackDisplayName = "gocd-slack-bot"
slackUserIconURL = "http://example.com/slack-bot.png"
displayMaterialChanges = true
process-all-rules = true
proxy {
hostname = "localhost"
port = "5555"
Expand All @@ -40,6 +41,7 @@ gocd.slack {
- `webhookUrl` - Slack Webhook URL
- `channel` - Override the default channel where we should send the notifications in slack. You can also give a value starting with `@` to send it to any specific user.
- `displayMaterialChanges` - Display material changes in the notification (git revisions for example). Defaults to true, set to false if you want to hide.
- `process-all-rules` - If true, all matching rules are applied instead of just the first.
- `proxy` - Specify proxy related settings for the plugin.
- `proxy.hostname` - Proxy Host
- `proxy.port` - Proxy Port
Expand Down Expand Up @@ -67,7 +69,7 @@ gocd.slack {
}]
}
```
`gocd.slack.pipelines` contains all the rules for the go-server. It is a list of rules (see below for what the parameters mean) for various pipelines. The plugin will pick the first matching pipeline rule from the pipelines collection above, so your most specific rule should be first, with the most generic rule at the bottom.
`gocd.slack.pipelines` contains all the rules for the go-server. It is a list of rules (see below for what the parameters mean) for various pipelines. The plugin will pick the first matching pipeline rule from the pipelines collection above, so your most specific rule should be first, with the most generic rule at the bottom. Alternatively, set the `process-all-rules` option to `true` and all matching rules will be applied.
- `name` - Regex to match the pipeline name
- `stage` - Regex to match the stage name
- `state` - State of the pipeline at which we should send a notification. You can provide multiple values separated by pipe (`|`) symbol. Valid values are passed, failed, cancelled, building, fixed, broken or all.
Expand Down
16 changes: 11 additions & 5 deletions src/main/java/in/ashwanthkumar/gocd/slack/PipelineListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import in.ashwanthkumar.gocd.slack.ruleset.Rules;
import in.ashwanthkumar.utils.lang.option.Option;

import java.util.List;

abstract public class PipelineListener {
private Logger LOG = Logger.getLoggerFor(PipelineListener.class);
protected Rules rules;
Expand All @@ -17,11 +19,15 @@ public PipelineListener(Rules rules) {
public void notify(GoNotificationMessage message) throws Exception {
message.tryToFixStageResult(rules);
LOG.debug(String.format("Finding rules with state %s", message.getStageResult()));
Option<PipelineRule> ruleOption = rules.find(message.getPipelineName(), message.getStageName(), message.getStageResult());
if (ruleOption.isDefined()) {
PipelineRule pipelineRule = ruleOption.get();
LOG.debug(String.format("Matching rule is %s", pipelineRule));
handlePipelineStatus(pipelineRule, PipelineStatus.valueOf(message.getStageResult().toUpperCase()), message);
List<PipelineRule> foundRules = rules.find(message.getPipelineName(), message.getStageName(), message.getStageResult());
if (foundRules.size() > 0) {
for (PipelineRule pipelineRule : foundRules) {
LOG.debug(String.format("Matching rule is %s", pipelineRule));
handlePipelineStatus(pipelineRule, PipelineStatus.valueOf(message.getStageResult().toUpperCase()), message);
if (! rules.getProcessAllRules()) {
break;
}
}
} else {
LOG.warn(String.format("Couldn't find any matching rule for %s/%s with status=%s", message.getPipelineName(), message.getStageName(), message.getStageResult()));
}
Expand Down
33 changes: 30 additions & 3 deletions src/main/java/in/ashwanthkumar/gocd/slack/ruleset/Rules.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class Rules {
private String goLogin;
private String goPassword;
private boolean displayMaterialChanges;
private boolean processAllRules;

private Proxy proxy;

Expand Down Expand Up @@ -139,6 +140,15 @@ public Rules setDisplayMaterialChanges(boolean displayMaterialChanges) {
return this;
}

public boolean getProcessAllRules() {
return processAllRules;
}

public Rules setProcessAllRules(boolean processAllRules) {
this.processAllRules = processAllRules;
return this;
}

public Proxy getProxy() {
return proxy;
}
Expand All @@ -152,12 +162,23 @@ public PipelineListener getPipelineListener() {
return pipelineListener;
}

public Option<PipelineRule> find(final String pipeline, final String stage, final String pipelineStatus) {
return Lists.find(pipelineRules, new Predicate<PipelineRule>() {
public List<PipelineRule> find(final String pipeline, final String stage, final String pipelineStatus) {
Predicate<PipelineRule> predicate = new Predicate<PipelineRule>() {
public Boolean apply(PipelineRule input) {
return input.matches(pipeline, stage, pipelineStatus);
}
});
};

if(processAllRules) {
return Lists.filter(pipelineRules, predicate);
} else {
List<PipelineRule> found = new ArrayList<PipelineRule>();
Option<PipelineRule> match = Lists.find(pipelineRules, predicate);
if(match.isDefined()) {
found.add(match.get());
}
return found;
}
}

public static Rules fromConfig(Config config) {
Expand Down Expand Up @@ -199,6 +220,11 @@ public static Rules fromConfig(Config config) {
displayMaterialChanges = config.getBoolean("displayMaterialChanges");
}

boolean processAllRules = false;
if (config.hasPath("process-all-rules")) {
processAllRules = config.getBoolean("process-all-rules");
}

Proxy proxy = null;
if (config.hasPath("proxy")) {
Config proxyConfig = config.getConfig("proxy");
Expand Down Expand Up @@ -231,6 +257,7 @@ public PipelineRule apply(Config input) {
.setGoLogin(login)
.setGoPassword(password)
.setDisplayMaterialChanges(displayMaterialChanges)
.setProcessAllRules(processAllRules)
.setProxy(proxy);
try {
rules.pipelineListener = Class.forName(config.getString("listener")).asSubclass(PipelineListener.class).getConstructor(Rules.class).newInstance(rules);
Expand Down
108 changes: 62 additions & 46 deletions src/test/java/in/ashwanthkumar/gocd/slack/ruleset/RulesTest.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package in.ashwanthkumar.gocd.slack.ruleset;


import in.ashwanthkumar.gocd.slack.Status;
import in.ashwanthkumar.utils.lang.option.Option;
import org.junit.Test;

import java.util.Arrays;
import java.util.List;
import java.util.HashSet;
import java.util.Set;

Expand All @@ -17,34 +17,30 @@ public class RulesTest {
@Test
public void shouldFindMatch() {
Rules rules = new Rules();
PipelineRule pRules1 = new PipelineRule("pipeline", "stage");
pRules1.setStatus(new HashSet<PipelineStatus>(Arrays.asList(PipelineStatus.PASSED, PipelineStatus.FAILED)));

rules.setPipelineRules(Arrays.asList(
pipelineRule("pipeline1", "stage1", "ch1", statuses(PipelineStatus.BUILDING, PipelineStatus.FAILED)),
pipelineRule("pipeline1", "stage2", "ch2", statuses(PipelineStatus.FIXED, PipelineStatus.PASSED)),
pipelineRule("pipeline2", "stage2", "ch3", statuses(PipelineStatus.CANCELLED, PipelineStatus.BROKEN))
));

Option<PipelineRule> rule1 = rules.find("pipeline1", "stage1", Status.Building.getStatus());
assertThat(rule1.isDefined(), is(true));
assertThat(rule1.get().getNameRegex(), is("pipeline1"));
assertThat(rule1.get().getStageRegex(), is("stage1"));
List<PipelineRule> foundRules1 = rules.find("pipeline1", "stage1", Status.Building.getStatus());
assertThat(foundRules1.size(), is(1));
assertThat(foundRules1.get(0).getNameRegex(), is("pipeline1"));
assertThat(foundRules1.get(0).getStageRegex(), is("stage1"));

Option<PipelineRule> rule2 = rules.find("pipeline2", "stage2", Status.Cancelled.getStatus());
assertThat(rule2.isDefined(), is(true));
assertThat(rule2.get().getNameRegex(), is("pipeline2"));
assertThat(rule2.get().getStageRegex(), is("stage2"));
List<PipelineRule> foundRules2 = rules.find("pipeline2", "stage2", Status.Cancelled.getStatus());
assertThat(foundRules2.size(), is(1));
assertThat(foundRules2.get(0).getNameRegex(), is("pipeline2"));
assertThat(foundRules2.get(0).getStageRegex(), is("stage2"));

Option<PipelineRule> rule3 = rules.find("pipeline2", "stage2", Status.Passed.getStatus());
assertThat(rule3.isDefined(), is(false));
List<PipelineRule> foundRules3 = rules.find("pipeline2", "stage2", Status.Passed.getStatus());
assertThat(foundRules3.size(), is(0));
}

@Test
public void shouldFindMatchWithRegexp() {
Rules rules = new Rules();
PipelineRule pRules1 = new PipelineRule("pipeline", "stage");
pRules1.setStatus(new HashSet<PipelineStatus>(Arrays.asList(PipelineStatus.PASSED, PipelineStatus.FAILED)));

rules.setPipelineRules(Arrays.asList(
pipelineRule("[a-z]*", "[a-z]*", "ch1", statuses(PipelineStatus.BUILDING)),
Expand All @@ -53,46 +49,66 @@ public void shouldFindMatchWithRegexp() {
pipelineRule("\\d*", "[a-z]*", "ch4", statuses(PipelineStatus.BUILDING))
));

Option<PipelineRule> rule1 = rules.find("abc", "efg", Status.Building.getStatus());
assertThat(rule1.isDefined(), is(true));
assertThat(rule1.get().getNameRegex(), is("[a-z]*"));
assertThat(rule1.get().getStageRegex(), is("[a-z]*"));
assertThat(rule1.get().getChannel(), is("ch1"));

Option<PipelineRule> rule2 = rules.find("123", "456", Status.Building.getStatus());
assertThat(rule2.isDefined(), is(true));
assertThat(rule2.get().getNameRegex(), is("\\d*"));
assertThat(rule2.get().getStageRegex(), is("\\d*"));
assertThat(rule2.get().getChannel(), is("ch2"));

Option<PipelineRule> rule3 = rules.find("123", "456", Status.Passed.getStatus());
assertThat(rule3.isDefined(), is(true));
assertThat(rule3.get().getNameRegex(), is("\\d*"));
assertThat(rule3.get().getStageRegex(), is("\\d*"));
assertThat(rule3.get().getChannel(), is("ch3"));

Option<PipelineRule> rule4 = rules.find("pipeline1", "stage1", Status.Passed.getStatus());
assertThat(rule4.isDefined(), is(false));
List<PipelineRule> foundRules1 = rules.find("abc", "efg", Status.Building.getStatus());
assertThat(foundRules1.size(), is(1));
assertThat(foundRules1.get(0).getNameRegex(), is("[a-z]*"));
assertThat(foundRules1.get(0).getStageRegex(), is("[a-z]*"));
assertThat(foundRules1.get(0).getChannel(), is("ch1"));

List<PipelineRule> foundRules2 = rules.find("123", "456", Status.Building.getStatus());
assertThat(foundRules2.size(), is(1));
assertThat(foundRules2.get(0).getNameRegex(), is("\\d*"));
assertThat(foundRules2.get(0).getStageRegex(), is("\\d*"));
assertThat(foundRules2.get(0).getChannel(), is("ch2"));

List<PipelineRule> foundRules3 = rules.find("123", "456", Status.Passed.getStatus());
assertThat(foundRules3.size(), is(1));
assertThat(foundRules3.get(0).getNameRegex(), is("\\d*"));
assertThat(foundRules3.get(0).getStageRegex(), is("\\d*"));
assertThat(foundRules3.get(0).getChannel(), is("ch3"));

List<PipelineRule> foundRules4 = rules.find("pipeline1", "stage1", Status.Passed.getStatus());
assertThat(foundRules4.size(), is(0));
}
@Test
public void shouldFindAllMatchesIfProcessAllRules() {
Rules rules = new Rules();
rules.setProcessAllRules(true);

rules.setPipelineRules(Arrays.asList(
pipelineRule("[a-z]*", "stage\\d+", "ch1", statuses(PipelineStatus.BUILDING)),
pipelineRule("[a-z]*", "stage2", "ch2", statuses(PipelineStatus.BUILDING))
));

List<PipelineRule> foundRules1 = rules.find("abc", "stage1", Status.Building.getStatus());
assertThat(foundRules1.size(), is(1));
assertThat(foundRules1.get(0).getChannel(), is("ch1"));

List<PipelineRule> foundRules2 = rules.find("abc", "stage2", Status.Building.getStatus());
assertThat(foundRules2.size(), is(2));
assertThat(foundRules2.get(0).getChannel(), is("ch1"));
assertThat(foundRules2.get(1).getChannel(), is("ch2"));

List<PipelineRule> foundRules3 = rules.find("abc1", "stage2", Status.Building.getStatus());
assertThat(foundRules3.size(), is(0));
}

@Test
public void shouldFindMatchAll() {
Rules rules = new Rules();
PipelineRule pRules1 = new PipelineRule("pipeline", "stage");
pRules1.setStatus(new HashSet<PipelineStatus>(Arrays.asList(PipelineStatus.PASSED, PipelineStatus.FAILED)));

rules.setPipelineRules(Arrays.asList(
pipelineRule("p1", "s1", "ch1", statuses(PipelineStatus.ALL))
));

assertThat(rules.find("p1", "s1", Status.Building.getStatus()).isDefined(), is(true));
assertThat(rules.find("p1", "s1", Status.Broken.getStatus()).isDefined(), is(true));
assertThat(rules.find("p1", "s1", Status.Cancelled.getStatus()).isDefined(), is(true));
assertThat(rules.find("p1", "s1", Status.Failed.getStatus()).isDefined(), is(true));
assertThat(rules.find("p1", "s1", Status.Failing.getStatus()).isDefined(), is(true));
assertThat(rules.find("p1", "s1", Status.Fixed.getStatus()).isDefined(), is(true));
assertThat(rules.find("p1", "s1", Status.Passed.getStatus()).isDefined(), is(true));
assertThat(rules.find("p1", "s1", Status.Unknown.getStatus()).isDefined(), is(true));
assertThat(rules.find("p1", "s1", Status.Building.getStatus()).size(), is(1));
assertThat(rules.find("p1", "s1", Status.Broken.getStatus()).size(), is(1));
assertThat(rules.find("p1", "s1", Status.Cancelled.getStatus()).size(), is(1));
assertThat(rules.find("p1", "s1", Status.Failed.getStatus()).size(), is(1));
assertThat(rules.find("p1", "s1", Status.Failing.getStatus()).size(), is(1));
assertThat(rules.find("p1", "s1", Status.Fixed.getStatus()).size(), is(1));
assertThat(rules.find("p1", "s1", Status.Passed.getStatus()).size(), is(1));
assertThat(rules.find("p1", "s1", Status.Unknown.getStatus()).size(), is(1));
}

@Test
Expand All @@ -117,4 +133,4 @@ private static Set<PipelineStatus> statuses(PipelineStatus... statuses) {
return new HashSet<PipelineStatus>(Arrays.asList(statuses));
}

}
}

0 comments on commit 0deb3cf

Please sign in to comment.