Skip to content

Commit c1d4492

Browse files
committed
Merge in changes from nikos/snsnotify-plugin master branch.
2 parents 7868b00 + 073c543 commit c1d4492

File tree

8 files changed

+152
-57
lines changed

8 files changed

+152
-57
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
target
22
work
3+
4+
# IntelliJ project files
5+
*.ipr
6+
*.iml
7+
*.iws

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
snsnotify-plugin
2+
================
3+
4+
Sends build notifications to an AWS SNS topic as post-build step with
5+
customizable subject and message payload.
6+
7+
1. `git clone https://github.com/jenkinsci/snsnotify-plugin`
8+
2. `cd snsnotify-plugin`
9+
3. `mvn hpi:run` compile and start Jetty with the Plugin ready to be used
10+
11+
Create an installable artifact:
12+
13+
1. `mvn clean install`
14+
2. (wait for mvn to download the internet)
15+
3. Manage Jenkins > Plugins > Advanced > Upload ```./target/snsnotify.hpi```
16+
4. Restart Jenkins ([$JENKINS_URL]/restart)
17+
18+
Now, login to AWS and do the following:
19+
20+
1. Create an SNS Topic, subscribe a target SQS queue (or create subscription via email etc.)
21+
2. Right-click on targeted SQS queue to confirm subscription
22+
23+
Finally, back to Jenkins...
24+
25+
1. Manage Jenkins > Configure Jenkins to use AWS creds and newly created Topic ARN
26+
2. As part of your job: add post-build step for SNS notification, optionally configure subject and message (you can make use of build and environment variables, which do get substituted), resp. override Topic ARN (if you do not want to stick with globally configured one).

pom.xml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>org.jenkins-ci.plugins</groupId>
77
<artifactId>plugin</artifactId>
8-
<version>1.553</version>
8+
<version>1.565.1</version>
99
</parent>
1010

1111
<artifactId>snsnotify</artifactId>
@@ -20,6 +20,14 @@
2020
<id>mikewatt</id>
2121
<name>Michael Watt</name>
2222
</developer>
23+
<developer>
24+
<id>jkelabora</id>
25+
<name>Julian Kelabora</name>
26+
</developer>
27+
<developer>
28+
<id>nikos</id>
29+
<name>Niko Schmuck</name>
30+
</developer>
2331
</developers>
2432

2533
<scm>

src/main/java/org/jenkinsci/plugins/snsnotify/AmazonSNSNotifier.java

Lines changed: 95 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3,90 +3,120 @@
33
import com.amazonaws.auth.BasicAWSCredentials;
44
import com.amazonaws.services.sns.AmazonSNSClient;
55
import com.amazonaws.services.sns.model.PublishRequest;
6-
import hudson.Launcher;
6+
import hudson.EnvVars;
77
import hudson.Extension;
8+
import hudson.Launcher;
89
import hudson.Util;
910
import hudson.model.AbstractBuild;
1011
import hudson.model.AbstractProject;
1112
import hudson.model.BuildListener;
1213
import hudson.model.Hudson;
13-
import hudson.model.Result;
14-
import hudson.tasks.Notifier;
15-
import hudson.tasks.Publisher;
1614
import hudson.tasks.BuildStepDescriptor;
1715
import hudson.tasks.BuildStepMonitor;
16+
import hudson.tasks.Notifier;
17+
import hudson.tasks.Publisher;
1818
import net.sf.json.JSONObject;
19+
import org.apache.commons.lang.StringUtils;
1920
import org.kohsuke.stapler.DataBoundConstructor;
2021
import org.kohsuke.stapler.StaplerRequest;
2122

23+
import java.io.IOException;
24+
import java.util.logging.Logger;
25+
2226
public class AmazonSNSNotifier extends Notifier {
2327

28+
private final static Logger LOG = Logger.getLogger(AmazonSNSNotifier.class.getName());
29+
2430
private final String projectTopicArn;
31+
private final String subjectTemplate;
32+
private final String messageTemplate;
2533

2634
@DataBoundConstructor
27-
public AmazonSNSNotifier(String projectTopicArn) {
35+
public AmazonSNSNotifier(String projectTopicArn, String subjectTemplate, String messageTemplate) {
2836
this.projectTopicArn = projectTopicArn;
37+
this.subjectTemplate = subjectTemplate;
38+
this.messageTemplate = messageTemplate;
2939
}
3040

3141
public String getProjectTopicArn() {
3242
return projectTopicArn;
3343
}
3444

35-
@Override
45+
public String getSubjectTemplate() {
46+
return subjectTemplate;
47+
}
48+
49+
public String getMessageTemplate() {
50+
return messageTemplate;
51+
}
52+
3653
public BuildStepMonitor getRequiredMonitorService() {
3754
return BuildStepMonitor.NONE;
3855
}
3956

4057
@Override
41-
public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) {
42-
43-
if (build.getResult() == Result.FAILURE || build.getResult() == Result.UNSTABLE) {
44-
45-
String awsAccessKey = getDescriptor().getAwsAccessKey();
46-
String awsSecretKey = getDescriptor().getAwsSecretKey();
47-
String publishTopic = isEmpty(projectTopicArn) ?
48-
getDescriptor().getDefaultTopicArn() : projectTopicArn;
49-
50-
if (isEmpty(publishTopic)) {
51-
listener.error(
52-
"No global or project topic ARN sent; cannot send SNS notification");
53-
return true;
54-
}
55-
56-
if (isEmpty(awsAccessKey) || isEmpty(awsSecretKey)) {
57-
listener.error(
58-
"AWS credentials not configured; cannot send SNS notification");
59-
return true;
60-
}
61-
62-
String snsApiEndpoint = getSNSApiEndpoint(publishTopic);
63-
if (isEmpty(snsApiEndpoint)) {
64-
listener.error(
65-
"Could not determine SNS API Endpoint from topic ARN: " + publishTopic);
66-
return true;
67-
}
68-
69-
String subject = truncate(
70-
String.format("Build %s: %s",
71-
build.getResult().toString(), build.getFullDisplayName()), 100);
72-
73-
String message = Hudson.getInstance().getRootUrl() == null ?
74-
Util.encode("(Global build server url not set)/" + build.getUrl()) :
75-
Util.encode(Hudson.getInstance().getRootUrl() + build.getUrl());
76-
77-
AmazonSNSClient snsClient = new AmazonSNSClient(
78-
new BasicAWSCredentials(awsAccessKey, awsSecretKey));
79-
snsClient.setEndpoint(snsApiEndpoint);
80-
81-
try {
82-
PublishRequest pubReq = new PublishRequest(publishTopic, message, subject);
83-
snsClient.publish(pubReq);
84-
} catch (Exception e) {
85-
listener.error(
86-
"Failed to send SNS notification: " + e.getMessage());
87-
} finally {
88-
snsClient.shutdown();
89-
}
58+
public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException {
59+
60+
String awsAccessKey = getDescriptor().getAwsAccessKey();
61+
String awsSecretKey = getDescriptor().getAwsSecretKey();
62+
String publishTopic = isEmpty(projectTopicArn) ?
63+
getDescriptor().getDefaultTopicArn() : projectTopicArn;
64+
65+
if (isEmpty(publishTopic)) {
66+
listener.error(
67+
"No global or project topic ARN sent; cannot send SNS notification");
68+
return true;
69+
}
70+
71+
if (isEmpty(awsAccessKey) || isEmpty(awsSecretKey)) {
72+
listener.error(
73+
"AWS credentials not configured; cannot send SNS notification");
74+
return true;
75+
}
76+
77+
String snsApiEndpoint = getSNSApiEndpoint(publishTopic);
78+
if (isEmpty(snsApiEndpoint)) {
79+
listener.error(
80+
"Could not determine SNS API Endpoint from topic ARN: " + publishTopic);
81+
return true;
82+
}
83+
84+
// ~~ prepare subject (incl. variable replacement)
85+
String subject;
86+
if (StringUtils.isEmpty(subjectTemplate)) {
87+
subject = truncate(
88+
String.format("Build %s: %s",
89+
build.getResult().toString(), build.getFullDisplayName()), 100);
90+
} else {
91+
subject = replaceVariables(build, listener, subjectTemplate);
92+
}
93+
94+
// ~~ prepare message (incl. variable replacement)
95+
String message;
96+
if (StringUtils.isEmpty(messageTemplate)) {
97+
message = Hudson.getInstance().getRootUrl() == null ?
98+
Util.encode("(Global build server url not set)/" + build.getUrl()) :
99+
Util.encode(Hudson.getInstance().getRootUrl() + build.getUrl());
100+
} else {
101+
message = replaceVariables(build, listener, messageTemplate);
102+
}
103+
104+
LOG.info("Setup SNS client '" + snsApiEndpoint + "' ...");
105+
AmazonSNSClient snsClient = new AmazonSNSClient(
106+
new BasicAWSCredentials(awsAccessKey, awsSecretKey));
107+
snsClient.setEndpoint(snsApiEndpoint);
108+
109+
try {
110+
String summary = String.format("subject=%s message=%s topic=%s", subject, message, publishTopic);
111+
LOG.info("Publish SNS notification: " + summary + " ...");
112+
PublishRequest pubReq = new PublishRequest(publishTopic, message, subject);
113+
snsClient.publish(pubReq);
114+
listener.getLogger().println("Published SNS notification: " + summary);
115+
} catch (Exception e) {
116+
listener.error(
117+
"Failed to send SNS notification: " + e.getMessage());
118+
} finally {
119+
snsClient.shutdown();
90120
}
91121

92122
return true;
@@ -108,6 +138,16 @@ private boolean isEmpty(String s) {
108138
return s == null || s.trim().length() == 0;
109139
}
110140

141+
/**
142+
* Replaces all build and environment variables given by the String tmpl.
143+
*/
144+
private String replaceVariables(AbstractBuild build, BuildListener listener, String tmpl)
145+
throws IOException, InterruptedException {
146+
EnvVars envVars = build.getEnvironment(listener);
147+
String result = Util.replaceMacro(tmpl, build.getBuildVariableResolver());
148+
return Util.replaceMacro(result, envVars);
149+
}
150+
111151
/**
112152
* Determine the SNS API endpoint to make API calls to, based on the region
113153
* included in the topic ARN.

src/main/resources/index.jelly

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
<div>
2-
Send failed/unstable build notifications to an Amazon SNS Topic
2+
Send build notifications to an Amazon SNS Topic
33
</div>

src/main/resources/org/jenkinsci/plugins/snsnotify/AmazonSNSNotifier/config.jelly

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,12 @@
44
<f:textbox />
55
</f:entry>
66

7+
<f:entry title="Subject (default: Build {BUILD_RESULT} {BUILD_FULLDISPLAYNAME})" field="subjectTemplate">
8+
<f:textbox />
9+
</f:entry>
10+
11+
<f:entry title="Message (default: {BUILD_URL})" field="messageTemplate">
12+
<f:textbox />
13+
</f:entry>
14+
715
</j:jelly>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<div>
2+
Specifies the message (payload) as published to the SNS topic.
3+
Build variables can be used and are resolved before message is sent.
4+
</div>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<div>
2+
Specifies the subject of the message published to the SNS topic.
3+
Build variables can be used and are resolved before message is sent.
4+
</div>

0 commit comments

Comments
 (0)