@@ -61,10 +61,201 @@ const SCHEMA_BUILD_DATA = Joi.object().keys({
6161 ...schema . plugins . notifications . schemaBuildData ,
6262 settings : SCHEMA_SLACK_SETTINGS . required ( )
6363} ) ;
64+ const SCHEMA_JOB_DATA = Joi . object ( ) . keys ( {
65+ ...schema . plugins . notifications . schemaJobData ,
66+ settings : SCHEMA_SLACK_SETTINGS . required ( )
67+ } ) ;
6468const SCHEMA_SLACK_CONFIG = Joi . object ( ) . keys ( {
6569 token : Joi . string ( ) . required ( )
6670} ) ;
6771
72+ /**
73+ * Handle slack messaging for build status
74+ * @method buildStatus
75+ * @param {Object } buildData
76+ * @param {String } buildData.status Build status
77+ * @param {Object } buildData.pipeline Pipeline
78+ * @param {String } buildData.jobName Job name
79+ * @param {Object } buildData.build Build
80+ * @param {Object } buildData.event Event
81+ * @param {String } buildData.buildLink Build link
82+ * @param {Object } buildData.settings Notification setting
83+ * @param {Object } config Slack notifications config
84+ */
85+ function buildStatus ( buildData , config ) {
86+ try {
87+ Joi . attempt ( buildData , SCHEMA_BUILD_DATA , 'Invalid build data format' ) ;
88+ } catch ( e ) {
89+ return ;
90+ }
91+
92+ // Slack channel overwrite from meta data. Job specific only.
93+ const metaReplaceVar = `build.meta.notification.slack.${ buildData . jobName } .channels` ;
94+
95+ const metaDataSlackChannel = hoek . reach ( buildData , metaReplaceVar , { default : false } ) ;
96+
97+ let channelReplacement ;
98+
99+ if ( metaDataSlackChannel ) {
100+ channelReplacement = metaDataSlackChannel . split ( ',' ) ;
101+ // Remove empty/blank items.
102+ channelReplacement = channelReplacement . filter ( x => x . trim ( ) !== '' ) ;
103+ }
104+ // Slack channels from configuration
105+ if ( typeof buildData . settings . slack === 'string' || Array . isArray ( buildData . settings . slack ) ) {
106+ buildData . settings . slack =
107+ typeof buildData . settings . slack === 'string' ? [ buildData . settings . slack ] : buildData . settings . slack ;
108+ buildData . settings . slack = {
109+ channels : buildData . settings . slack ,
110+ statuses : DEFAULT_STATUSES ,
111+ minimized : false
112+ } ;
113+ }
114+ if ( channelReplacement ) {
115+ buildData . settings . slack . channels = channelReplacement ;
116+ }
117+
118+ if ( buildData . settings . slack . statuses === undefined ) {
119+ buildData . settings . slack . statuses = DEFAULT_STATUSES ;
120+ }
121+
122+ // Add for fixed notification
123+ if ( buildData . isFixed ) {
124+ buildData . settings . slack . statuses . push ( 'FIXED' ) ;
125+ }
126+
127+ // Do not change the `buildData.status` directly
128+ // It affects the behavior of other notification plugins
129+ let notificationStatus = buildData . status ;
130+
131+ if ( buildData . settings . slack . statuses . includes ( 'FAILURE' ) ) {
132+ if ( notificationStatus === 'SUCCESS' && buildData . isFixed ) {
133+ notificationStatus = 'FIXED' ;
134+ }
135+ }
136+
137+ if ( ! buildData . settings . slack . statuses . includes ( notificationStatus ) ) {
138+ return ;
139+ }
140+
141+ const pipelineLink = buildData . buildLink . split ( '/builds' ) [ 0 ] ;
142+ const truncatedSha = buildData . event . sha . slice ( 0 , 6 ) ;
143+ const cutOff = 150 ;
144+ const commitMessage =
145+ buildData . event . commit . message . length > cutOff
146+ ? `${ buildData . event . commit . message . substring ( 0 , cutOff ) } ...`
147+ : buildData . event . commit . message ;
148+
149+ // Slack channel overwrite from meta data. Job specific only.
150+ const metaMinimizedReplaceVar = `build.meta.notification.slack.${ buildData . jobName } .minimized` ;
151+ const isMinimized = hoek . reach ( buildData , metaMinimizedReplaceVar , {
152+ default : buildData . settings . slack . minimized
153+ } ) ;
154+
155+ let message = isMinimized
156+ ? // eslint-disable-next-line max-len
157+ `<${ pipelineLink } |${ buildData . pipeline . scmRepo . name } #${ buildData . jobName } > *${ notificationStatus } *`
158+ : // eslint-disable-next-line max-len
159+ `*${ notificationStatus } * ${ STATUSES_MAP [ notificationStatus ] } <${ pipelineLink } |${ buildData . pipeline . scmRepo . name } ${ buildData . jobName } >` ;
160+
161+ const rootDir = hoek . reach ( buildData , 'pipeline.scmRepo.rootDir' , { default : false } ) ;
162+
163+ if ( rootDir ) {
164+ message = `${ message } \n*Source Directory:* ${ rootDir } ` ;
165+ }
166+
167+ const metaMessage = hoek . reach ( buildData , 'build.meta.notification.slack.message' , { default : false } ) ;
168+ const metaVar = `build.meta.notification.slack.${ buildData . jobName } .message` ;
169+ const buildMessage = hoek . reach ( buildData , metaVar , { default : false } ) ;
170+
171+ // Use job specific message over generic message.
172+ if ( buildMessage ) {
173+ message = `${ message } \n${ buildMessage } ` ;
174+ } else if ( metaMessage ) {
175+ message = `${ message } \n${ metaMessage } ` ;
176+ }
177+
178+ const attachments = isMinimized
179+ ? [
180+ {
181+ fallback : '' ,
182+ color : COLOR_MAP [ notificationStatus ] ,
183+ fields : [
184+ {
185+ title : 'Build' ,
186+ value : `<${ buildData . buildLink } |#${ buildData . build . id } >` ,
187+ short : true
188+ }
189+ ]
190+ }
191+ ]
192+ : [
193+ {
194+ fallback : '' ,
195+ color : COLOR_MAP [ notificationStatus ] ,
196+ title : `#${ buildData . build . id } ` ,
197+ title_link : `${ buildData . buildLink } ` ,
198+ // eslint-disable-next-line max-len
199+ text :
200+ `${ commitMessage } (<${ buildData . event . commit . url } |${ truncatedSha } >)` +
201+ `\n${ buildData . event . causeMessage } `
202+ }
203+ ] ;
204+
205+ const slackMessage = {
206+ message,
207+ attachments
208+ } ;
209+
210+ slacker ( config . token , buildData . settings . slack . channels , slackMessage ) ;
211+ }
212+
213+ /**
214+ * Handle slack messaging for job status
215+ * @method jobStatus
216+ * @param {Object } jobData
217+ * @param {String } jobData.status Status
218+ * @param {Object } jobData.pipeline Pipeline
219+ * @param {String } jobData.jobName Job name
220+ * @param {String } jobData.pipelineLink Pipeline link
221+ * @param {String } jobData.message Message
222+ * @param {Object } jobData.settings Notification setting
223+ * @param {Object } config Slack notifications config
224+ */
225+ function jobStatus ( jobData , config ) {
226+ try {
227+ Joi . attempt ( jobData , SCHEMA_JOB_DATA , 'Invalid job data format' ) ;
228+ } catch ( e ) {
229+ return ;
230+ }
231+
232+ // Slack channels from configuration
233+ if ( typeof jobData . settings . slack === 'string' || Array . isArray ( jobData . settings . slack ) ) {
234+ jobData . settings . slack =
235+ typeof jobData . settings . slack === 'string' ? [ jobData . settings . slack ] : jobData . settings . slack ;
236+ jobData . settings . slack = {
237+ channels : jobData . settings . slack ,
238+ statuses : DEFAULT_STATUSES ,
239+ minimized : false
240+ } ;
241+ }
242+
243+ const isMinimized = jobData . settings . slack . minimized ;
244+ const message = isMinimized
245+ ? // eslint-disable-next-line max-len
246+ `<${ jobData . pipelineLink } |${ jobData . pipeline . scmRepo . name } #${ jobData . jobName } > *${ jobData . status } *\n${ jobData . message } `
247+ : // eslint-disable-next-line max-len
248+ `*${ jobData . status } * ${ STATUSES_MAP [ jobData . status ] } <${ jobData . pipelineLink } |${
249+ jobData . pipeline . scmRepo . name
250+ } ${ jobData . jobName } >\n${ jobData . message } `;
251+
252+ const slackMessage = {
253+ message
254+ } ;
255+
256+ slacker ( config . token , jobData . settings . slack . channels , slackMessage ) ;
257+ }
258+
68259class SlackNotifier extends NotificationBase {
69260 /**
70261 * Constructs an SlackNotifier
@@ -78,139 +269,24 @@ class SlackNotifier extends NotificationBase {
78269
79270 /**
80271 * Sets listener on server event of name 'eventName' in Screwdriver
81- * Currently, event is triggered with a build status is updated
82272 * @method _notify
83- * @param {Object } buildData - Build data emitted with some event from Screwdriver
273+ * @param {String } event - Event emitted from Screwdriver
274+ * @param {Object } payload - Data emitted with some event from Screwdriver
84275 */
85- _notify ( buildData ) {
86- // Check buildData format against SCHEMA_BUILD_DATA
87- try {
88- Joi . attempt ( buildData , SCHEMA_BUILD_DATA , 'Invalid build data format' ) ;
89- } catch ( e ) {
90- return ;
91- }
92- if ( Object . keys ( buildData . settings ) . length === 0 ) {
93- return ;
94- }
95-
96- // Slack channel overwrite from meta data. Job specific only.
97- const metaReplaceVar = `build.meta.notification.slack.${ buildData . jobName } .channels` ;
98-
99- const metaDataSlackChannel = hoek . reach ( buildData , metaReplaceVar , { default : false } ) ;
100-
101- let channelReplacement ;
102-
103- if ( metaDataSlackChannel ) {
104- channelReplacement = metaDataSlackChannel . split ( ',' ) ;
105- // Remove empty/blank items.
106- channelReplacement = channelReplacement . filter ( x => x . trim ( ) !== '' ) ;
107- }
108- // Slack channels from configuration
109- if ( typeof buildData . settings . slack === 'string' || Array . isArray ( buildData . settings . slack ) ) {
110- buildData . settings . slack =
111- typeof buildData . settings . slack === 'string' ? [ buildData . settings . slack ] : buildData . settings . slack ;
112- buildData . settings . slack = {
113- channels : buildData . settings . slack ,
114- statuses : DEFAULT_STATUSES ,
115- minimized : false
116- } ;
117- }
118- if ( channelReplacement ) {
119- buildData . settings . slack . channels = channelReplacement ;
120- }
121-
122- if ( buildData . settings . slack . statuses === undefined ) {
123- buildData . settings . slack . statuses = DEFAULT_STATUSES ;
124- }
125-
126- // Add for fixed notification
127- if ( buildData . isFixed ) {
128- buildData . settings . slack . statuses . push ( 'FIXED' ) ;
129- }
130-
131- // Do not change the `buildData.status` directly
132- // It affects the behavior of other notification plugins
133- let notificationStatus = buildData . status ;
134-
135- if ( buildData . settings . slack . statuses . includes ( 'FAILURE' ) ) {
136- if ( notificationStatus === 'SUCCESS' && buildData . isFixed ) {
137- notificationStatus = 'FIXED' ;
138- }
139- }
140-
141- if ( ! buildData . settings . slack . statuses . includes ( notificationStatus ) ) {
276+ _notify ( event , payload ) {
277+ if ( ! payload || ! payload . settings || Object . keys ( payload . settings ) . length === 0 ) {
142278 return ;
143279 }
144- const pipelineLink = buildData . buildLink . split ( '/builds' ) [ 0 ] ;
145- const truncatedSha = buildData . event . sha . slice ( 0 , 6 ) ;
146- const cutOff = 150 ;
147- const commitMessage =
148- buildData . event . commit . message . length > cutOff
149- ? `${ buildData . event . commit . message . substring ( 0 , cutOff ) } ...`
150- : buildData . event . commit . message ;
151-
152- // Slack channel overwrite from meta data. Job specific only.
153- const metaMinimizedReplaceVar = `build.meta.notification.slack.${ buildData . jobName } .minimized` ;
154- const isMinimized = hoek . reach ( buildData , metaMinimizedReplaceVar , {
155- default : buildData . settings . slack . minimized
156- } ) ;
157-
158- let message = isMinimized
159- ? // eslint-disable-next-line max-len
160- `<${ pipelineLink } |${ buildData . pipeline . scmRepo . name } #${ buildData . jobName } > *${ notificationStatus } *`
161- : // eslint-disable-next-line max-len
162- `*${ notificationStatus } * ${ STATUSES_MAP [ notificationStatus ] } <${ pipelineLink } |${ buildData . pipeline . scmRepo . name } ${ buildData . jobName } >` ;
163-
164- const rootDir = hoek . reach ( buildData , 'pipeline.scmRepo.rootDir' , { default : false } ) ;
165-
166- if ( rootDir ) {
167- message = `${ message } \n*Source Directory:* ${ rootDir } ` ;
168- }
169-
170- const metaMessage = hoek . reach ( buildData , 'build.meta.notification.slack.message' , { default : false } ) ;
171280
172- const metaVar = `build.meta.notification.slack.${ buildData . jobName } .message` ;
173-
174- const buildMessage = hoek . reach ( buildData , metaVar , { default : false } ) ;
175-
176- // Use job specific message over generic message.
177- if ( buildMessage ) {
178- message = `${ message } \n${ buildMessage } ` ;
179- } else if ( metaMessage ) {
180- message = `${ message } \n${ metaMessage } ` ;
281+ switch ( event ) {
282+ case 'build_status' :
283+ buildStatus ( payload , this . config ) ;
284+ break ;
285+ case 'job_status' :
286+ jobStatus ( payload , this . config ) ;
287+ break ;
288+ default :
181289 }
182- const attachments = isMinimized
183- ? [
184- {
185- fallback : '' ,
186- color : COLOR_MAP [ notificationStatus ] ,
187- fields : [
188- {
189- title : 'Build' ,
190- value : `<${ buildData . buildLink } |#${ buildData . build . id } >` ,
191- short : true
192- }
193- ]
194- }
195- ]
196- : [
197- {
198- fallback : '' ,
199- color : COLOR_MAP [ notificationStatus ] ,
200- title : `#${ buildData . build . id } ` ,
201- title_link : `${ buildData . buildLink } ` ,
202- // eslint-disable-next-line max-len
203- text :
204- `${ commitMessage } (<${ buildData . event . commit . url } |${ truncatedSha } >)` +
205- `\n${ buildData . event . causeMessage } `
206- }
207- ] ;
208- const slackMessage = {
209- message,
210- attachments
211- } ;
212-
213- slacker ( this . config . token , buildData . settings . slack . channels , slackMessage ) ;
214290 }
215291
216292 static validateConfig ( config ) {
0 commit comments