From eb117482d73d4c93d8b93654559a969b201cc3d8 Mon Sep 17 00:00:00 2001
From: Tim Jacomb <21194782+timja@users.noreply.github.com>
Date: Tue, 7 May 2024 15:11:33 +0100
Subject: [PATCH] Add better error handling for scopes and add app manifest
(#963)
---
README.md | 119 ++++++++----------
.../slack/pipeline/SlackUploadFileRunner.java | 13 +-
2 files changed, 64 insertions(+), 68 deletions(-)
diff --git a/README.md b/README.md
index 276a13d1..5ca8ba17 100644
--- a/README.md
+++ b/README.md
@@ -10,9 +10,8 @@ applications like [RocketChat][rocketchat] and [Mattermost][mattermost].
## Install Instructions for Slack
-1. Get a Slack account:
-2. Configure the Jenkins integration:
-3. Install this plugin on your Jenkins server:
+1. Get a Slack account:
+2. Install this plugin on your Jenkins server:
1. From the Jenkins homepage navigate to `Manage Jenkins`
2. Navigate to `Manage Plugins`,
@@ -22,6 +21,57 @@ applications like [RocketChat][rocketchat] and [Mattermost][mattermost].
![image][img-plugin-manager]
+3. Continue to the next section to create your Slack app.
+
+### Creating your app
+
+1. Go to and click "Create New App".
+2. Click `From an app manifest`
+3. Select your workspace
+4. Delete the example manifest that Slack provides
+5. Click YAML
+6. Paste the following into the text box:
+
+```yaml
+display_information:
+ name: Jenkins
+features:
+ bot_user:
+ display_name: Jenkins
+ always_online: true
+oauth_config:
+ scopes:
+ bot:
+ - channels:read
+ - chat:write
+ - chat:write.customize
+ - files:write
+ - reactions:write
+ - users:read
+ - users:read.email
+ - groups:read
+settings:
+ org_deploy_enabled: false
+ socket_mode_enabled: false
+ token_rotation_enabled: false
+```
+
+7. Click "Next"
+8. Click "Create"
+9. Click "Install App to Workspace"
+10. Click "Allow"
+11. Click "OAuth & Permissions" in the sidebar
+9. Copy the "Bot User OAuth Access Token"
+10. *On Jenkins*: Find the Slack configuration in "Manage Jenkins → System".
+ 1. *On Jenkins*: Click "Add" to create a new "Secret text" Credential with the bot user token.
+ 2. *On Jenkins*: Select the new "Secret text" in the dropdown.
+ 3. *On Jenkins*: Add a default channel (this can be removed after validating the connection works).
+ 4. *On Jenkins*: Tick the "Custom slack app bot user" option.
+11. Invite the Jenkins bot user into the Slack channel(s) you wish to be notified in.
+12. *On Jenkins*: Click test connection. A message will be sent to the default channel / default member.
+
+### Notify for all jobs
+
If you want to configure a notification to be sent to Slack for **all jobs**, you may want to also consider installing an additional plugin called [Global Slack Notifier plugin](https://plugins.jenkins.io/global-slack-notifier).
### Pipeline job
@@ -228,17 +278,6 @@ Any hex triplet (i.e. `'#AA1100'`) can be used for the color of the message. The
1. Configure it in your Jenkins job (and optionally as global configuration) and
**add it as a Post-build action**.
-## Install Instructions for Slack compatible application
-
-1. Log into the Slack compatible application.
-2. Create a Webhook (it may need to be enabled in system console) by visiting
- Integrations.
-3. You should now have a URL with a token. Something like
- `https://mydomain.com/hooks/xxxx` where `xxxx` is the integration token and
- `https://mydomain.com/hooks/` is the `Slack compatible app URL`.
-4. Install this plugin on your Jenkins server.
-5. Follow the freestyle or pipeline instructions for the slack installation instructions.
-
## Security
Use Jenkins Credentials and a credential ID to configure the Slack integration
@@ -285,62 +324,12 @@ unclassified:
slackNotifier:
teamDomain: # i.e. your-company (just the workspace name not the full url)
tokenCredentialId: slack-token
+ botUser: true
```
For more details see the configuration as code plugin documentation:
-## Bot user mode
-
-There's two ways to authenticate with slack using this plugin.
-
-1. Using the "Jenkins CI" app written by Slack,
- it's what is known as a 'legacy app' written directly into the slack code base and not maintained anymore.
-
-2. Creating your own custom "Slack app" and installing it to your workspace.
-
-The benefit of using your own custom "Slack app" is that you get to use all of the modern features that Slack has released in the last few years to
-Slack apps and not to legacy apps.
-
-These include:
-
-- Threading
-- File upload
-- Custom app emoji per message
-- Blocks
-
-The bot user option is not supported if you use the _Slack compatible app URL_
-option.
-
-### Creating your app
-
-Note: These docs may become outdated as Slack changes their website, if they do become outdated please send a PR here to update the docs.
-
-1. Go to and click "Create New App".
-2. Pick an app name, i.e. "Jenkins" and a workspace that you'll be installing it to.
-3. Click "Create App". This will leave you on the "Basic Information" screen for your new app.
-3. Scroll down to "Display Information" and fill it out. You can get the Jenkins logo from: .
-4. Scroll back up to "Add features and functionality".
-5. Click "Permissions" to navigate to the "OAuth & Permissions" page.
-6. Scroll down to "Scopes". Under "Bot Token Scopes"
- 1. Add `chat:write` Scope.
- 2. (optional) Add `files:write` Scope if you will be uploading files.
- 3. (optional) Add `chat:write.customize` Scope if you will be sending messages with a custom username and/or avatar.
- 4. (optional) Add `reactions:write` Scope if you will be [adding reactions](#emoji-reactions).
- 5. (optional) Add `users:read` and `users:read.email` Scope if you will be [looking users up by email](#user-id-look-up).
-7. (optional) Click "App Home" in the sidebar
- 1. (optional) Edit the slack display name for the bot.
- 2. Return to the "OAuth & Permissions" page.
-8. At the top of the page, click "Install App to Workspace". This will generate a "Bot User OAuth Access Token".
-9. Copy the "Bot User OAuth Access Token".
-10. *On Jenkins*: Find the Slack configuration in "Manage Jenkins → Configure System".
- 1. *On Jenkins*: Click "Add" to create a new "Secret text" Credential with that token.
- 2. *On Jenkins*: Select the new "Secret text" in the dropdown.
- 3. *On Jenkins*: Make note of the "Default channel / member id".
- 4. *On Jenkins*: Tick the "Custom slack app bot user" option.
-11. Invite the Jenkins bot user into the Slack channel(s) you wish to be notified in.
-12. *On Jenkins*: Click test connection. A message will be sent to the default channel / default member.
-
## Troubleshooting connection failure
When testing the connection, you may see errors like:
diff --git a/src/main/java/jenkins/plugins/slack/pipeline/SlackUploadFileRunner.java b/src/main/java/jenkins/plugins/slack/pipeline/SlackUploadFileRunner.java
index cc5c833d..3fd363ca 100644
--- a/src/main/java/jenkins/plugins/slack/pipeline/SlackUploadFileRunner.java
+++ b/src/main/java/jenkins/plugins/slack/pipeline/SlackUploadFileRunner.java
@@ -162,14 +162,16 @@ private static JSONArray convertListToJsonArray(List fileIds) {
return jsonArray;
}
- private static ResponseHandler getStandardResponseHandler() {
+ private ResponseHandler getStandardResponseHandler() {
return response -> {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 && status < 300) {
HttpEntity entity = response.getEntity();
return entity != null ? new JSONObject(EntityUtils.toString(entity)) : null;
} else {
- logger.log(Level.WARNING, UPLOAD_FAILED_TEMPLATE + status);
+ String errorMessage = UPLOAD_FAILED_TEMPLATE + status + " " + EntityUtils.toString(response.getEntity());
+ listener.getLogger().println(errorMessage);
+ logger.log(Level.WARNING, errorMessage);
return null;
}
};
@@ -191,7 +193,12 @@ private String convertChannelNameToId(String channelName, CloseableHttpClient cl
ResponseHandler standardResponseHandler = getStandardResponseHandler();
JSONObject result = client.execute(requestBuilder.build(), standardResponseHandler);
- if (result == null || !result.getBoolean("ok")) {
+ if (result == null) {
+ // logging should have been done in the result handler where the response is available
+ return null;
+ }
+ if (!result.getBoolean("ok")) {
+ listener.getLogger().println("Couldn't convert channel name to ID in Slack: " + result);
return null;
}