diff --git a/README.md b/README.md index 9937aec5..ff54d9dc 100755 --- a/README.md +++ b/README.md @@ -21,6 +21,13 @@ Create a new ***Secret text*** credential: Select that credential as the value for the ***Integration Token Credential ID*** field: ![image](https://cloud.githubusercontent.com/assets/983526/17971458/ec296bf6-6aa8-11e6-8d19-06d9f1c9d611.png) + +#### Bot user option +This plugin supports sending notifications via bot users. You can enable bot user support from both +global and project configurations. If the notification will be sent to a user via direct message, +default integration sends it via @slackbot, you can use this option if you want to send messages via a bot user. +You need to provide credentials of the bot user for integration token credentials to use this feature. + #### Jenkins Pipeline Support Includes [Jenkins Pipeline](https://github.com/jenkinsci/workflow-plugin) support as of version 2.0: diff --git a/src/main/java/jenkins/plugins/slack/SlackNotifier.java b/src/main/java/jenkins/plugins/slack/SlackNotifier.java index 4878e89a..05e644d3 100755 --- a/src/main/java/jenkins/plugins/slack/SlackNotifier.java +++ b/src/main/java/jenkins/plugins/slack/SlackNotifier.java @@ -43,6 +43,7 @@ public class SlackNotifier extends Notifier { private String teamDomain; private String authToken; private String authTokenCredentialId; + private boolean botUser; private String room; private String sendAs; private boolean startNotification; @@ -91,6 +92,10 @@ public String getAuthTokenCredentialId() { return authTokenCredentialId; } + public boolean getBotUser() { + return botUser; + } + public String getSendAs() { return sendAs; } @@ -192,7 +197,7 @@ public void setCustomMessage(String customMessage) { } @DataBoundConstructor - public SlackNotifier(final String teamDomain, final String authToken, final String room, final String authTokenCredentialId, + public SlackNotifier(final String teamDomain, final String authToken, final boolean botUser, final String room, final String authTokenCredentialId, final String sendAs, final boolean startNotification, final boolean notifyAborted, final boolean notifyFailure, final boolean notifyNotBuilt, final boolean notifySuccess, final boolean notifyUnstable, final boolean notifyBackToNormal, final boolean notifyRepeatedFailure, final boolean includeTestSummary, CommitInfoChoice commitInfoChoice, @@ -201,6 +206,7 @@ public SlackNotifier(final String teamDomain, final String authToken, final Stri this.teamDomain = teamDomain; this.authToken = authToken; this.authTokenCredentialId = StringUtils.trim(authTokenCredentialId); + this.botUser = botUser; this.room = room; this.sendAs = sendAs; this.startNotification = startNotification; @@ -227,8 +233,10 @@ public SlackService newSlackService(AbstractBuild r, BuildListener listener) { teamDomain = getDescriptor().getTeamDomain(); } String authToken = this.authToken; + boolean botUser = this.botUser; if (StringUtils.isEmpty(authToken)) { authToken = getDescriptor().getToken(); + botUser = getDescriptor().getBotUser(); } String authTokenCredentialId = this.authTokenCredentialId; if (StringUtils.isEmpty(authTokenCredentialId)) { @@ -251,7 +259,7 @@ public SlackService newSlackService(AbstractBuild r, BuildListener listener) { authTokenCredentialId = env.expand(authTokenCredentialId); room = env.expand(room); - return new StandardSlackService(teamDomain, authToken, authTokenCredentialId, room); + return new StandardSlackService(teamDomain, authToken, authTokenCredentialId, botUser, room); } @Override @@ -279,6 +287,7 @@ public static class DescriptorImpl extends BuildStepDescriptor { private String teamDomain; private String token; private String tokenCredentialId; + private boolean botUser; private String room; private String sendAs; @@ -300,6 +309,10 @@ public String getTokenCredentialId() { return tokenCredentialId; } + public boolean getBotUser() { + return botUser; + } + public String getRoom() { return room; } @@ -337,6 +350,7 @@ public SlackNotifier newInstance(StaplerRequest sr, JSONObject json) { String teamDomain = sr.getParameter("slackTeamDomain"); String token = sr.getParameter("slackToken"); String tokenCredentialId = json.getString("tokenCredentialId"); + boolean botUser = "true".equals(sr.getParameter("slackBotUser")); String room = sr.getParameter("slackRoom"); boolean startNotification = "true".equals(sr.getParameter("slackStartNotification")); boolean notifySuccess = "true".equals(sr.getParameter("slackNotifySuccess")); @@ -350,7 +364,7 @@ public SlackNotifier newInstance(StaplerRequest sr, JSONObject json) { CommitInfoChoice commitInfoChoice = CommitInfoChoice.forDisplayName(sr.getParameter("slackCommitInfoChoice")); boolean includeCustomMessage = "on".equals(sr.getParameter("includeCustomMessage")); String customMessage = sr.getParameter("customMessage"); - return new SlackNotifier(teamDomain, token, room, tokenCredentialId, sendAs, startNotification, notifyAborted, + return new SlackNotifier(teamDomain, token, botUser, room, tokenCredentialId, sendAs, startNotification, notifyAborted, notifyFailure, notifyNotBuilt, notifySuccess, notifyUnstable, notifyBackToNormal, notifyRepeatedFailure, includeTestSummary, commitInfoChoice, includeCustomMessage, customMessage); } @@ -360,14 +374,15 @@ public boolean configure(StaplerRequest sr, JSONObject formData) throws FormExce teamDomain = sr.getParameter("slackTeamDomain"); token = sr.getParameter("slackToken"); tokenCredentialId = formData.getJSONObject("slack").getString("tokenCredentialId"); + botUser = "true".equals(sr.getParameter("slackBotUser")); room = sr.getParameter("slackRoom"); sendAs = sr.getParameter("slackSendAs"); save(); return super.configure(sr, formData); } - SlackService getSlackService(final String teamDomain, final String authToken, final String authTokenCredentialId, final String room) { - return new StandardSlackService(teamDomain, authToken, authTokenCredentialId, room); + SlackService getSlackService(final String teamDomain, final String authToken, final String authTokenCredentialId, final boolean botUser, final String room) { + return new StandardSlackService(teamDomain, authToken, authTokenCredentialId, botUser, room); } @Override @@ -378,6 +393,7 @@ public String getDisplayName() { public FormValidation doTestConnection(@QueryParameter("slackTeamDomain") final String teamDomain, @QueryParameter("slackToken") final String authToken, @QueryParameter("tokenCredentialId") final String authTokenCredentialId, + @QueryParameter("slackBotUser") final boolean botUser, @QueryParameter("slackRoom") final String room) throws FormException { try { String targetDomain = teamDomain; @@ -385,8 +401,10 @@ public FormValidation doTestConnection(@QueryParameter("slackTeamDomain") final targetDomain = this.teamDomain; } String targetToken = authToken; + boolean targetBotUser = botUser; if (StringUtils.isEmpty(targetToken)) { targetToken = this.token; + targetBotUser = this.botUser; } String targetTokenCredentialId = authTokenCredentialId; if (StringUtils.isEmpty(targetTokenCredentialId)) { @@ -396,7 +414,7 @@ public FormValidation doTestConnection(@QueryParameter("slackTeamDomain") final if (StringUtils.isEmpty(targetRoom)) { targetRoom = this.room; } - SlackService testSlackService = getSlackService(targetDomain, targetToken, targetTokenCredentialId, targetRoom); + SlackService testSlackService = getSlackService(targetDomain, targetToken, targetTokenCredentialId, targetBotUser, targetRoom); String message = "Slack/Jenkins plugin: you're all set on " + DisplayURLProvider.get().getRoot(); boolean success = testSlackService.publish(message, "good"); return success ? FormValidation.ok("Success") : FormValidation.error("Failure"); @@ -411,6 +429,7 @@ public static class SlackJobProperty extends hudson.model.JobProperty + + + + diff --git a/src/main/resources/jenkins/plugins/slack/SlackNotifier/global.jelly b/src/main/resources/jenkins/plugins/slack/SlackNotifier/global.jelly index 6077129f..d7725a30 100755 --- a/src/main/resources/jenkins/plugins/slack/SlackNotifier/global.jelly +++ b/src/main/resources/jenkins/plugins/slack/SlackNotifier/global.jelly @@ -21,6 +21,9 @@ + + + diff --git a/src/main/resources/jenkins/plugins/slack/workflow/SlackSendStep/config.jelly b/src/main/resources/jenkins/plugins/slack/workflow/SlackSendStep/config.jelly index c90e0868..cf48487a 100644 --- a/src/main/resources/jenkins/plugins/slack/workflow/SlackSendStep/config.jelly +++ b/src/main/resources/jenkins/plugins/slack/workflow/SlackSendStep/config.jelly @@ -17,6 +17,9 @@ + + + diff --git a/src/main/webapp/help-globalConfig-botUser.html b/src/main/webapp/help-globalConfig-botUser.html new file mode 100644 index 00000000..5fceabb6 --- /dev/null +++ b/src/main/webapp/help-globalConfig-botUser.html @@ -0,0 +1,4 @@ +
+

Bot user option indicates the token belongs to a bot user in Slack.

+

If the notification will be sent to a user via direct message, the default integration sends it via @slackbot, use this option if you want to send messages via a bot user.

+
\ No newline at end of file diff --git a/src/main/webapp/help-projectConfig-botUser.html b/src/main/webapp/help-projectConfig-botUser.html new file mode 100644 index 00000000..5fceabb6 --- /dev/null +++ b/src/main/webapp/help-projectConfig-botUser.html @@ -0,0 +1,4 @@ +
+

Bot user option indicates the token belongs to a bot user in Slack.

+

If the notification will be sent to a user via direct message, the default integration sends it via @slackbot, use this option if you want to send messages via a bot user.

+
\ No newline at end of file diff --git a/src/test/java/jenkins/plugins/slack/SlackNotifierStub.java b/src/test/java/jenkins/plugins/slack/SlackNotifierStub.java index 4a92a96a..ac84a56d 100644 --- a/src/test/java/jenkins/plugins/slack/SlackNotifierStub.java +++ b/src/test/java/jenkins/plugins/slack/SlackNotifierStub.java @@ -2,12 +2,12 @@ public class SlackNotifierStub extends SlackNotifier { - public SlackNotifierStub(String teamDomain, String authToken, String authTokenCredentialId, String room, + public SlackNotifierStub(String teamDomain, String authToken, boolean botUser, String room, String authTokenCredentialId, String sendAs, boolean startNotification, boolean notifyAborted, boolean notifyFailure, boolean notifyNotBuilt, boolean notifySuccess, boolean notifyUnstable, boolean notifyBackToNormal, boolean notifyRepeatedFailure, boolean includeTestSummary, CommitInfoChoice commitInfoChoice, boolean includeCustomMessage, String customMessage) { - super(teamDomain, authToken, authTokenCredentialId, room, sendAs, startNotification, notifyAborted, notifyFailure, + super(teamDomain, authToken, botUser, room, authTokenCredentialId, sendAs, startNotification, notifyAborted, notifyFailure, notifyNotBuilt, notifySuccess, notifyUnstable, notifyBackToNormal, notifyRepeatedFailure, includeTestSummary, commitInfoChoice, includeCustomMessage, customMessage); } @@ -21,7 +21,7 @@ public synchronized void load() { } @Override - SlackService getSlackService(final String teamDomain, final String authToken, final String authTokenCredentialId, final String room) { + SlackService getSlackService(final String teamDomain, final String authToken, final String authTokenCredentialId, final boolean botUser, final String room) { return slackService; } diff --git a/src/test/java/jenkins/plugins/slack/SlackNotifierTest.java b/src/test/java/jenkins/plugins/slack/SlackNotifierTest.java index ccc38c8d..b216681d 100644 --- a/src/test/java/jenkins/plugins/slack/SlackNotifierTest.java +++ b/src/test/java/jenkins/plugins/slack/SlackNotifierTest.java @@ -52,7 +52,7 @@ public void testDoTestConnection() { } descriptor.setSlackService(slackServiceStub); try { - FormValidation result = descriptor.doTestConnection("teamDomain", "authToken", "authTokenCredentialId", "room"); + FormValidation result = descriptor.doTestConnection("teamDomain", "authToken", "authTokenCredentialId", false,"room"); assertEquals(result.kind, expectedResult); } catch (Descriptor.FormException e) { e.printStackTrace(); diff --git a/src/test/java/jenkins/plugins/slack/StandardSlackServiceStub.java b/src/test/java/jenkins/plugins/slack/StandardSlackServiceStub.java index 2bee39ae..eb7d6230 100644 --- a/src/test/java/jenkins/plugins/slack/StandardSlackServiceStub.java +++ b/src/test/java/jenkins/plugins/slack/StandardSlackServiceStub.java @@ -4,8 +4,8 @@ public class StandardSlackServiceStub extends StandardSlackService { private HttpClientStub httpClientStub; - public StandardSlackServiceStub(String teamDomain, String token, String tokenCredentialId, String roomId) { - super(teamDomain, token, tokenCredentialId, roomId); + public StandardSlackServiceStub(String teamDomain, String token, String tokenCredentialId, boolean botUser, String roomId) { + super(teamDomain, token, tokenCredentialId, botUser, roomId); } @Override diff --git a/src/test/java/jenkins/plugins/slack/StandardSlackServiceTest.java b/src/test/java/jenkins/plugins/slack/StandardSlackServiceTest.java index 69539da6..48f90d1f 100755 --- a/src/test/java/jenkins/plugins/slack/StandardSlackServiceTest.java +++ b/src/test/java/jenkins/plugins/slack/StandardSlackServiceTest.java @@ -13,7 +13,7 @@ public class StandardSlackServiceTest { */ @Test public void publishWithBadHostShouldNotRethrowExceptions() { - StandardSlackService service = new StandardSlackService("foo", "token", null, "#general"); + StandardSlackService service = new StandardSlackService("foo", "token", null, false, "#general"); service.setHost("hostvaluethatwillcausepublishtofail"); service.publish("message"); } @@ -23,7 +23,7 @@ public void publishWithBadHostShouldNotRethrowExceptions() { */ @Test public void invalidTeamDomainShouldFail() { - StandardSlackService service = new StandardSlackService("my", "token", null, "#general"); + StandardSlackService service = new StandardSlackService("my", "token", null, false, "#general"); service.publish("message"); } @@ -32,13 +32,13 @@ public void invalidTeamDomainShouldFail() { */ @Test public void invalidTokenShouldFail() { - StandardSlackService service = new StandardSlackService("tinyspeck", "token", null, "#general"); + StandardSlackService service = new StandardSlackService("tinyspeck", "token", null, false, "#general"); service.publish("message"); } @Test public void publishToASingleRoomSendsASingleMessage() { - StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, "#room1"); + StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, false, "#room1"); HttpClientStub httpClientStub = new HttpClientStub(); service.setHttpClient(httpClientStub); service.publish("message"); @@ -47,7 +47,7 @@ public void publishToASingleRoomSendsASingleMessage() { @Test public void publishToMultipleRoomsSendsAMessageToEveryRoom() { - StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, "#room1,#room2,#room3"); + StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, false, "#room1,#room2,#room3"); HttpClientStub httpClientStub = new HttpClientStub(); service.setHttpClient(httpClientStub); service.publish("message"); @@ -56,7 +56,7 @@ public void publishToMultipleRoomsSendsAMessageToEveryRoom() { @Test public void successfulPublishToASingleRoomReturnsTrue() { - StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, "#room1"); + StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, false, "#room1"); HttpClientStub httpClientStub = new HttpClientStub(); httpClientStub.setHttpStatus(HttpStatus.SC_OK); service.setHttpClient(httpClientStub); @@ -65,7 +65,7 @@ public void successfulPublishToASingleRoomReturnsTrue() { @Test public void successfulPublishToMultipleRoomsReturnsTrue() { - StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, "#room1,#room2,#room3"); + StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, false, "#room1,#room2,#room3"); HttpClientStub httpClientStub = new HttpClientStub(); httpClientStub.setHttpStatus(HttpStatus.SC_OK); service.setHttpClient(httpClientStub); @@ -74,7 +74,7 @@ public void successfulPublishToMultipleRoomsReturnsTrue() { @Test public void failedPublishToASingleRoomReturnsFalse() { - StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, "#room1"); + StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, false, "#room1"); HttpClientStub httpClientStub = new HttpClientStub(); httpClientStub.setHttpStatus(HttpStatus.SC_NOT_FOUND); service.setHttpClient(httpClientStub); @@ -83,7 +83,7 @@ public void failedPublishToASingleRoomReturnsFalse() { @Test public void singleFailedPublishToMultipleRoomsReturnsFalse() { - StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, "#room1,#room2,#room3"); + StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, false, "#room1,#room2,#room3"); HttpClientStub httpClientStub = new HttpClientStub(); httpClientStub.setFailAlternateResponses(true); httpClientStub.setHttpStatus(HttpStatus.SC_OK); @@ -93,7 +93,17 @@ public void singleFailedPublishToMultipleRoomsReturnsFalse() { @Test public void publishToEmptyRoomReturnsTrue() { - StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, ""); + StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, false, ""); + HttpClientStub httpClientStub = new HttpClientStub(); + httpClientStub.setHttpStatus(HttpStatus.SC_OK); + service.setHttpClient(httpClientStub); + assertTrue(service.publish("message")); + } + + + @Test + public void sendAsBotUserReturnsTrue() { + StandardSlackServiceStub service = new StandardSlackServiceStub("domain", "token", null, true, "#room1"); HttpClientStub httpClientStub = new HttpClientStub(); httpClientStub.setHttpStatus(HttpStatus.SC_OK); service.setHttpClient(httpClientStub); diff --git a/src/test/java/jenkins/plugins/slack/config/BackwordsCompatible_1_8_SlackNotifierTest.java b/src/test/java/jenkins/plugins/slack/config/BackwordsCompatible_1_8_SlackNotifierTest.java index f5bf011d..c474200d 100644 --- a/src/test/java/jenkins/plugins/slack/config/BackwordsCompatible_1_8_SlackNotifierTest.java +++ b/src/test/java/jenkins/plugins/slack/config/BackwordsCompatible_1_8_SlackNotifierTest.java @@ -42,6 +42,7 @@ public void testBasicMigration() { assertEquals("jenkins-slack-plugin", notifier.getTeamDomain()); assertEquals("auth-token-for-test", notifier.getAuthToken()); + assertEquals(false, notifier.getBotUser()); assertEquals("#slack-plugin-testing", notifier.getRoom()); assertFalse(notifier.getStartNotification()); @@ -68,6 +69,7 @@ public void testGlobalSettingsOverriden() { assertEquals("jenkins-slack-plugin", notifier.getTeamDomain()); assertEquals("auth-token-for-test", notifier.getAuthToken()); + assertEquals(false, notifier.getBotUser()); assertEquals("#slack-plugin-testing", notifier.getRoom()); assertFalse(notifier.getStartNotification()); @@ -94,6 +96,7 @@ public void testGlobalSettingsNotOverridden() throws IOException { assertEquals("", notifier.getTeamDomain()); assertEquals("", notifier.getAuthToken()); + assertEquals(false, notifier.getBotUser()); assertEquals("", notifier.getRoom()); assertFalse(notifier.getStartNotification()); @@ -148,6 +151,7 @@ public void testMigrationOfSomeJobs() throws IOException { assertEquals("", notifier.getTeamDomain()); assertEquals("", notifier.getAuthToken()); + assertEquals(false, notifier.getBotUser()); assertEquals("", notifier.getRoom()); assertTrue(notifier.getStartNotification()); diff --git a/src/test/java/jenkins/plugins/slack/workflow/SlackSendStepTest.java b/src/test/java/jenkins/plugins/slack/workflow/SlackSendStepTest.java index f0431935..87fa9720 100644 --- a/src/test/java/jenkins/plugins/slack/workflow/SlackSendStepTest.java +++ b/src/test/java/jenkins/plugins/slack/workflow/SlackSendStepTest.java @@ -56,6 +56,7 @@ public void testStepOverrides() throws Exception { SlackSendStep slackSendStep = new SlackSendStep("message"); slackSendStep.setToken("token"); slackSendStep.setTokenCredentialId("tokenCredentialId"); + slackSendStep.setBotUser(false); slackSendStep.setTeamDomain("teamDomain"); slackSendStep.setChannel("channel"); slackSendStep.setColor("good"); @@ -66,16 +67,16 @@ public void testStepOverrides() throws Exception { stepExecution.listener = taskListenerMock; when(slackDescMock.getToken()).thenReturn("differentToken"); - + when(slackDescMock.getBotUser()).thenReturn(true); when(taskListenerMock.getLogger()).thenReturn(printStreamMock); doNothing().when(printStreamMock).println(); - when(stepExecution.getSlackService(anyString(), anyString(), anyString(), anyString())).thenReturn(slackServiceMock); + when(stepExecution.getSlackService(anyString(), anyString(), anyString(), anyBoolean(), anyString())).thenReturn(slackServiceMock); when(slackServiceMock.publish(anyString(), anyString())).thenReturn(true); stepExecution.run(); - verify(stepExecution, times(1)).getSlackService("teamDomain", "token", "tokenCredentialId", "channel"); + verify(stepExecution, times(1)).getSlackService("teamDomain", "token", "tokenCredentialId", false, "channel"); verify(slackServiceMock, times(1)).publish("message", "good"); assertFalse(stepExecution.step.isFailOnError()); } @@ -93,15 +94,16 @@ public void testValuesForGlobalConfig() throws Exception { when(slackDescMock.getTeamDomain()).thenReturn("globalTeamDomain"); when(slackDescMock.getToken()).thenReturn("globalToken"); when(slackDescMock.getTokenCredentialId()).thenReturn("globalTokenCredentialId"); + when(slackDescMock.getBotUser()).thenReturn(false); when(slackDescMock.getRoom()).thenReturn("globalChannel"); when(taskListenerMock.getLogger()).thenReturn(printStreamMock); doNothing().when(printStreamMock).println(); - when(stepExecution.getSlackService(anyString(), anyString(), anyString(), anyString())).thenReturn(slackServiceMock); + when(stepExecution.getSlackService(anyString(), anyString(), anyString(), anyBoolean(), anyString())).thenReturn(slackServiceMock); stepExecution.run(); - verify(stepExecution, times(1)).getSlackService("globalTeamDomain", "globalToken", "globalTokenCredentialId", "globalChannel"); + verify(stepExecution, times(1)).getSlackService("globalTeamDomain", "globalToken", "globalTokenCredentialId", false, "globalChannel"); verify(slackServiceMock, times(1)).publish("message", ""); assertNull(stepExecution.step.getTeamDomain()); assertNull(stepExecution.step.getToken()); @@ -125,7 +127,7 @@ public void testNonNullEmptyColor() throws Exception { when(taskListenerMock.getLogger()).thenReturn(printStreamMock); doNothing().when(printStreamMock).println(); - when(stepExecution.getSlackService(anyString(), anyString(), anyString(), anyString())).thenReturn(slackServiceMock); + when(stepExecution.getSlackService(anyString(), anyString(), anyString(), anyBoolean(), anyString())).thenReturn(slackServiceMock); stepExecution.run(); verify(slackServiceMock, times(1)).publish("message", ""); diff --git a/src/test/resources/jenkins/plugins/slack/config/BackwordsCompatible_1_8_SlackNotifierTest/testGlobalSettingsNotOverridden/jobs/Test_Slack_Plugin/config.xml b/src/test/resources/jenkins/plugins/slack/config/BackwordsCompatible_1_8_SlackNotifierTest/testGlobalSettingsNotOverridden/jobs/Test_Slack_Plugin/config.xml index 73edbacb..7b976eaf 100644 --- a/src/test/resources/jenkins/plugins/slack/config/BackwordsCompatible_1_8_SlackNotifierTest/testGlobalSettingsNotOverridden/jobs/Test_Slack_Plugin/config.xml +++ b/src/test/resources/jenkins/plugins/slack/config/BackwordsCompatible_1_8_SlackNotifierTest/testGlobalSettingsNotOverridden/jobs/Test_Slack_Plugin/config.xml @@ -38,6 +38,7 @@ +