33import com .amazonaws .auth .BasicAWSCredentials ;
44import com .amazonaws .services .sns .AmazonSNSClient ;
55import com .amazonaws .services .sns .model .PublishRequest ;
6- import hudson .Launcher ;
6+ import hudson .EnvVars ;
77import hudson .Extension ;
8+ import hudson .Launcher ;
89import hudson .Util ;
910import hudson .model .AbstractBuild ;
1011import hudson .model .AbstractProject ;
1112import hudson .model .BuildListener ;
1213import hudson .model .Hudson ;
13- import hudson .model .Result ;
14- import hudson .tasks .Notifier ;
15- import hudson .tasks .Publisher ;
1614import hudson .tasks .BuildStepDescriptor ;
1715import hudson .tasks .BuildStepMonitor ;
16+ import hudson .tasks .Notifier ;
17+ import hudson .tasks .Publisher ;
1818import net .sf .json .JSONObject ;
19+ import org .apache .commons .lang .StringUtils ;
1920import org .kohsuke .stapler .DataBoundConstructor ;
2021import org .kohsuke .stapler .StaplerRequest ;
2122
23+ import java .io .IOException ;
24+ import java .util .logging .Logger ;
25+
2226public 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.
0 commit comments