Giter Club home page Giter Club logo

slack-help-bot's Introduction

Slack help bot

Listens for new posts in a designated Slack channel and raises a coresponding request in Jira.

Creating the Slack App

Steps
  1. Create a new app in your workspace.
  1. Head to socket mode and enable it. You will then be asked to create a new token (call it jira-integration) This will only have connections:write in the scope. Select Generate. Copy the generated token as this will be required for the slack-help-bot configuration.
  1. Head to Event subscriptions and enable it.
  1. Expand the Subscribe to bot events tab, add the following settings and save changes.
  1. Expand the Subscribe to events on behalf of users tab, add the following settings and save changes.
  1. Head to Interactivity and shortcuts and create a Global shortcut with the following settings and save changes.
  1. Head to Oauth and Permissions and install the app to your workspace. Allow the app the default permissions. Copy the generated Bot User OAuth Access Token as this will be required for the slack-help-bot configuration.
  1. Invite the app in the channel where you would like it to be used in Slack. Make a note of the channel ID as this will later be required in the slack-help-bot configuration. You can get the channel ID by right clicking, 'copy link', and then it will be the bit after archives in the url, e.g. C01APTJAM7D.

Getting Started with the Bot

Prerequisites

Running the application requires the following tools to be installed in your environment:

You need to create a Slack App as detailed in the steps above. For development purposes, this will have to be created in a new Slack workspace. You will also need the JIRA details. For development purposes, these values can be found in the "env.template.txt" file for the HMCTS Jira SBOX Project.

Set the relevant environment variables defined in env.template.txt based on above steps.

Running the application

We use 'Socket mode' so no need to proxy Slack's requests.

Running on Kubernetes

The application can be deployed on Kubernetes using the HMCTS nodejs chart. To avoid exposing sensitive data from the configuration above you can add them as secrets from an Azure Key Vault. See the chart documentation for further info.

Running locally

All configuration requirements listed above can be found in the "env.template.txt" file.

Rename "env.template.txt" to ".env" which is gitignored and safe for secrets.

Source into your shell with:

$ set -o allexport; source .env; set +o allexport

Install dependencies by executing the following command:

$ npm install

Run:

$ node app.js

Running locally with Docker

There is no need to source your configuration. The ".env" file will be mounted as a volume.

Create docker image:

  docker-compose build

Run the application by executing the following command:

  docker-compose up

This will start the frontend container exposing the application's port (set to 3000 in this template app).

In order to test if the application is up, you can visit https://localhost:3000/health in your browser. You should get a very basic health page (no styles, etc.).

slack-help-bot's People

Contributors

adusumillipraveen avatar danielwilsonkainos avatar dependabot[bot] avatar endakelly avatar gbstan92 avatar hannah38 avatar jakub-kozlowski avatar madjava avatar mokainos avatar msl8r avatar reespozzi avatar renovate-bot avatar renovate[bot] avatar shashisk97 avatar ssian2 avatar timja avatar tyler-35 avatar vijayrajagopalan-hmcts avatar willwatters avatar yarpo avatar zc-hmcts avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

slack-help-bot's Issues

Scan #platops-help For Similar Tickets Prior to Raising

What would you like to change?

Green Squad encounter a significant number of duplicate tikets for known issues that could easily be cut down if people opted to check #platops-help or #cloud-native-announce prior to raising their ticket like the workflow asks them. Implement code to check #platops-help for them.

This code should look for tickets raised in the last few (three?) days in the same project and environment with similar keywords in the ticket descriptor and then alert the user raising the form if any are found.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

docker-compose
docker-compose.yaml
dockerfile
Dockerfile
  • hmctspublic.azurecr.io/base/node 20-alpine
github-actions
.github/workflows/main.yml
  • actions/checkout v4
  • actions/setup-node v4
  • actions/github-script v7.0.1
  • azure/docker-login v2
npm
package.json
  • @hmcts/properties-volume ^1.0.0
  • @slack/bolt ^3.6.0
  • @types/config 3.3.4
  • @types/jira-client ^7.0.0
  • applicationinsights ^3.0.0
  • config ^3.3.6
  • jira-client ^8.1.0
  • js-yaml ^4.1.0
  • lodash ^4.17.21
  • prettier ^3.0.1
  • jest 29.7.0
  • jest-extended 4.0.2
nvm
.nvmrc
  • node 20.14.0
terraform
infrastructure/provider.tf
  • azurerm 3.107.0
  • hashicorp/terraform ~> 1.5.4

  • Check this box to trigger a request for Renovate to run again on this repository

Move SlackBot Forms From Workflow to Code

What would you like to change?

SlackBot's main entry point and form is configured to use the slack workflow builder, however this has proven both limiting and difficult to maintain. Move the form raising aspect of the workflow back into code so it can be modified easier and made more expansive.

Add command for changing a ticket type to BAU Task

What would you like to change?

It's easier for reporting and visibility if all tickets appear correctly, sometimes people raise as stories, tasks or bugs.

Rather than having to change through Jira and reminding people ourself it would be good if the bot could do it (and add a pre-canned comment).

@PlatOpsBot convert-to-bau DTSPO-111

there should also be a @PlatOpsBot help command as well

How do you think that would improve the project?

If this entry is related to a bug, please provide the steps to reproduce it

Crashed

}
[ERROR]  socket-mode:SocketModeClient:0 failed to send message on websocket: WebSocket is not open: readyState 3 (CLOSED)
Error: Failed to send message on websocket: WebSocket is not open: readyState 3 (CLOSED)
    at Object.websocketErrorWithOriginal (/opt/app/node_modules/@slack/socket-mode/dist/errors.js:29:33)
    at /opt/app/node_modules/@slack/socket-mode/dist/SocketModeClient.js:347:48
    at sendAfterClose (/opt/app/node_modules/ws/lib/websocket.js:907:5)
    at WebSocket.send (/opt/app/node_modules/ws/lib/websocket.js:405:7)
    at /opt/app/node_modules/@slack/socket-mode/dist/SocketModeClient.js:344:32
    at new Promise (<anonymous>)
    at SocketModeClient.send (/opt/app/node_modules/@slack/socket-mode/dist/SocketModeClient.js:329:16)
    at ack (/opt/app/node_modules/@slack/socket-mode/dist/SocketModeClient.js:469:24)
    at /opt/app/app.js:105:15
    at /opt/app/node_modules/@slack/bolt/dist/App.js:507:25
    at invokeMiddleware (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:21:16)
    at next (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:14:29)
    at Array.<anonymous> (/opt/app/node_modules/@slack/bolt/dist/middleware/builtin.js:166:15)
    at invokeMiddleware (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:13:53)
    at next (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:14:29)
    at Array.onlyShortcuts (/opt/app/node_modules/@slack/bolt/dist/middleware/builtin.js:30:11)
    at invokeMiddleware (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:13:53)
    at Object.processMiddleware (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:23:12)
    at /opt/app/node_modules/@slack/bolt/dist/App.js:505:42
    at Array.map (<anonymous>)
    at /opt/app/node_modules/@slack/bolt/dist/App.js:499:56
    at invokeMiddleware (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:21:16) {
  code: 'slack_socket_mode_websocket_error',
  original: Error: WebSocket is not open: readyState 3 (CLOSED)
      at sendAfterClose (/opt/app/node_modules/ws/lib/websocket.js:903:17)
      at WebSocket.send (/opt/app/node_modules/ws/lib/websocket.js:405:7)
      at /opt/app/node_modules/@slack/socket-mode/dist/SocketModeClient.js:344:32
      at new Promise (<anonymous>)
      at SocketModeClient.send (/opt/app/node_modules/@slack/socket-mode/dist/SocketModeClient.js:329:16)
      at ack (/opt/app/node_modules/@slack/socket-mode/dist/SocketModeClient.js:469:24)
      at /opt/app/app.js:105:15
      at /opt/app/node_modules/@slack/bolt/dist/App.js:507:25
      at invokeMiddleware (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:21:16)
      at next (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:14:29)
      at Array.<anonymous> (/opt/app/node_modules/@slack/bolt/dist/middleware/builtin.js:166:15)
      at invokeMiddleware (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:13:53)
      at next (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:14:29)
      at Array.onlyShortcuts (/opt/app/node_modules/@slack/bolt/dist/middleware/builtin.js:30:11)
      at invokeMiddleware (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:13:53)
      at Object.processMiddleware (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:23:12)
      at /opt/app/node_modules/@slack/bolt/dist/App.js:505:42
      at Array.map (<anonymous>)
      at /opt/app/node_modules/@slack/bolt/dist/App.js:499:56
      at invokeMiddleware (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:21:16)
      at next (/opt/app/node_modules/@slack/bolt/dist/middleware/process.js:14:29)
      at Array.<anonymous> (/opt/app/node_modules/@slack/bolt/dist/conversation-store.js:68:15)

appears to be slackapi/node-slack-sdk#1243

Simplify Ticket Raising Form

What would you like to change?

The SlackBot ticket raising form asks the user for all the information needed in the ticket in a single modal. This can not only be overwhenming but is also very inconvenient as it makes the rest of the user's slack inaccessible as if they at any point close the modal, they lose all the information they entered into it, forcing them to re-enter everything.

Rework the ticket raising form to include several smaller modals that can help atomise the information. Additionally, include edit buttons on the messages sent from SackBot so the user can ammend the data they've already entered. The information to raise the ticket will then be collected from the messages SlackBot sent the user and passed into the regular ticket raising routine like normal.

Analytics and Insights

What would you like to change?

SlackBot has the potential to be an insightful avenue for PlatOps, allowing us to gather data on the tickets being raised to Green Squad. The bot could report a variety of statistics on it's homepage, allowing PlatOps to identify problem points, which areas and teams need the most support and what the most common causes of tickets are.

Document gathering to be added to Jira ticket

When closing tickets there is a documentation gathering requirement, which is not added to the associated Jira ticket.

The documentation gathering contents should be added as a comment in the associated Jira ticket and also as a label.

Rework Documentation Gathering

What would you like to change?

SlackBot currently asks the individual closing a ticket to briefly document the steps taken to resolve it. The current implementation is entirely optional and takes too long to complete, leading to few instances of documentation that are not as helpful as they could be.

The current documentation modal presents three text boxes asking the user where what and how they resolved the ticket. Usually only one of these fields provides any useful information. Rework the documentation gathering step to include a single drop-down menu asking the user to categorise the issue and another optional comment box asking the user to briefly describe what they did. Closing the modal without selecting an option from the drop-down should not mark the ticket as 'resolved'.

Potential categories for ticket resolution:

  • User error
  • Lack of documentation
  • Lack of access
  • etc.

Split Text Fields Into Multiple Blocks if Range Limit is Exceeded

What would you like to change?

Current range checking implementation added in #76 simply truncates the message and refers the user to Jira. Slack's Bolt API only imposes the character limit for individual blocks within a message, so in theory, long messages can be split up into multiple blocks within the same message and the content of the help request can be displayed in full in slack.

See also: https://tools.hmcts.net/jira/browse/DTSPO-8056

How do you think that would improve the project?

If this entry is related to a bug, please provide the steps to reproduce it

Duplicate ticket button

Add a button to allow marking as a duplicate

Should popup a dropdown where you can put the ticket number

Then the slack message should be collapsed with a link to the parent ticket and a message in the thread saying this is closed as a duplicate

Jira ticket should be resolved as a duplicate

Auto-Select User's Team Based on AAD Group

What would you like to change?

To Expedite the ticket raising process, SlackBot could detect a user's team based on their email and AAD groups present in devops-azure-ad. SlackBot will need to authenticate with git to access the repository, download and parse the prod_users.yml file and detect the user's group based on what AAD groups they are in.

Alternatively, the bot could check the user's Team entry in their slack profile. That would probably be easier and more reliable ๐Ÿ™ƒ

The bot will also need to allow the user to select their team manually in the event the bot gets it wrong.

Bot can only duplicate plaintext ticket number

What would you like to change?

When using the duplicate feature, if the ticket number is a link, slackbot won't duplicate.

image

How do you think that would improve the project?

Increases speed/ease of duplicating ticket by being able to copy and paste DTSPO number.

Format code fence into jira code block

In both issue creation and in comments we could benefit from convert code fenced blocks to jira code markup

```
hello
```

to
{code}
{code}

bonus points for language support:

```yaml
my_yaml:
blah: true
```

to:

{code:yaml}
my_yaml:
blah: true
{code}

check all examples (doing from memory)

Add command for 'use-bot'

What would you like to change?

Add a trigger that allows us to add a pre-canned comment to a Jira ticket recommending people use the bot.

Should be something like:
@Platopsbot use-bot DTSPO-111

How do you think that would improve the project?

Not have to keep writing a message to people to use it and will make it easier and quicker to resolve tickets

If this entry is related to a bug, please provide the steps to reproduce it

Lost connection, required manual reboot

{"code":"slack_socket_mode_no_reply_received_error"}
[ERROR]  socket-mode:SocketModeClient:0 cannot send message when client is not connected
(node:1) UnhandledPromiseRejectionWarning: Error: Cannot send message when client is not connected
    at Object.sendWhileDisconnectedError (/opt/app/node_modules/@slack/socket-mode/dist/errors.js:56:26)
    at /opt/app/node_modules/@slack/socket-mode/dist/SocketModeClient.js:333:33
    at new Promise (<anonymous>)
    at SocketModeClient.send (/opt/app/node_modules/@slack/socket-mode/dist/SocketModeClient.js:329:16)
    at ack (/opt/app/node_modules/@slack/socket-mode/dist/SocketModeClient.js:466:24)
    at App.processEvent (/opt/app/node_modules/@slack/bolt/dist/App.js:424:19)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async SocketModeClient.<anonymous> (/opt/app/node_modules/@slack/bolt/dist/receivers/SocketModeReceiver.js:90:13)
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 308)

Bot will fail to post to slack if message is too long

The Slack Help Bot will error out when posting a ticket to slack if the 'analysis' field is too long. This will presumably also apply to every other field in the ticket as well. There appears to be a character limit of 3000 for every 'text' block imposed by the Bolt API that is not mentioned in the documentation ๐Ÿ™ƒ.

Range checks need to be implemented to the bot before it sends the message to slack. I believe the simplest option will simply be to simply cut fields off after 3000 characters and maybe put in a 'โ€ฆ' character to indicate it's been truncated. The JIRA API does not appear to impose a similar limit that I know of (if it does, it's much higher), so untruncated fields can probably be posted to JIRA just fine, that way we shouldn't lose any information when posting.

Logs from the error when it cropped up earlier today:

[ERROR]  bolt-app failed to match all allowed schemas [json-pointer:/blocks/1/text]
[ERROR]  bolt-app must be less than 3001 characters [json-pointer:/blocks/1/text/text]
[ERROR]  bolt-app Error: An API error occurred: invalid_blocks
    at platformErrorFromResult (/opt/app/node_modules/@slack/web-api/dist/errors.js:51:33)
    at WebClient.apiCall (/opt/app/node_modules/@slack/web-api/dist/WebClient.js:167:56)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async execute (/opt/app/app.js:255:26)
    at async processStepMiddleware (/opt/app/node_modules/@slack/bolt/dist/WorkflowStep.js:96:9)
    at async Array.<anonymous> (/opt/app/node_modules/@slack/bolt/dist/conversation-store.js:67:9)
    at async Array.<anonymous> (/opt/app/node_modules/@slack/bolt/dist/middleware/builtin.js:262:9)
    at async App.processEvent (/opt/app/node_modules/@slack/bolt/dist/App.js:536:13)
    at async SocketModeClient.<anonymous> (/opt/app/node_modules/@slack/bolt/dist/receivers/SocketModeReceiver.js:146:13) {
  code: 'slack_webapi_platform_error',
  data: {
    ok: false,
    error: 'invalid_blocks',
    errors: [
      'failed to match all allowed schemas [json-pointer:/blocks/1/text]',
      'must be less than 3001 characters [json-pointer:/blocks/1/text/text]'
    ],
    response_metadata: { messages: [Array], scopes: [Array], acceptedScopes: [Array] }
  }
}
node:internal/process/promises:279
            triggerUncaughtException(err, true /* fromPromise */);
            ^

Error: An API error occurred: invalid_blocks
    at platformErrorFromResult (/opt/app/node_modules/@slack/web-api/dist/errors.js:51:33)
    at WebClient.apiCall (/opt/app/node_modules/@slack/web-api/dist/WebClient.js:167:56)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async execute (/opt/app/app.js:255:26)
    at async processStepMiddleware (/opt/app/node_modules/@slack/bolt/dist/WorkflowStep.js:96:9)
    at async Array.<anonymous> (/opt/app/node_modules/@slack/bolt/dist/conversation-store.js:67:9)
    at async Array.<anonymous> (/opt/app/node_modules/@slack/bolt/dist/middleware/builtin.js:262:9)
    at async App.processEvent (/opt/app/node_modules/@slack/bolt/dist/App.js:536:13)
    at async SocketModeClient.<anonymous> (/opt/app/node_modules/@slack/bolt/dist/receivers/SocketModeReceiver.js:146:13) {
  code: 'slack_webapi_platform_error',
  data: {
    ok: false,
    error: 'invalid_blocks',
    errors: [
      'failed to match all allowed schemas [json-pointer:/blocks/1/text]',
      'must be less than 3001 characters [json-pointer:/blocks/1/text/text]'
    ],
    response_metadata: {
      messages: [
        '[ERROR] failed to match all allowed schemas [json-pointer:/blocks/1/text]',
        '[ERROR] must be less than 3001 characters [json-pointer:/blocks/1/text/text]'
      ],
      scopes: [
        'app_mentions:read',
        'channels:history',
        'commands',
        'chat:write',
        'chat:write.customize',
        'users.profile:read',
        'users:read',
        'users:read.email',
        'workflow.steps:execute',
        'reactions:write'
      ],
      acceptedScopes: [ 'chat:write' ]
    }
  }
}

Scan #cloud-native-announce For Known Issues Prior to Raising

What would you like to change?

Dependant on #162

Green Squad encounter a significant number of duplicate tikets for known issues that could easily be cut down if people opted to check #platops-help or #cloud-native-announce prior to raising their ticket like the workflow asks them. Implement code to check #cloud-native-announce for them.

This code should look for posts in #cloud-native-announce that mention the team, environment or certain keywords also present in the ticket descriptor or brief and alert the user if any are found prior to submitting the ticket.

Prompt Users for Feedback on The Ticket Raising Process

What would you like to change?

Continuous feedback and improvement is an important aspect of the BAU lifecycle. To reflect this, ask users who raise a ticket for their feedback on how the process went whenever their ticket is closed. Feedback should be anonymous, obtained via direct message from SlackBot and posted to a private slack channel.

Bot will attempt to mark issues as a duplicate of itself

Description

If the bot is used to mark a ticket as a duplicate of itself, it will attempt to do so, despite this not being allowed in JIRA. This will appear fine in Slack, but the changes will not be reflected in JIRA.

image

image

Error marking help request as duplicate in jira Error: You cannot link an issue to itself.
    at JiraApi.doRequest (/Users/sian/Git/slack-help-bot/node_modules/jira-client/lib/jira.js:333:15)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    at async markAsDuplicate (/Users/sian/Git/slack-help-bot/src/service/persistence.js:38:9)
    at async /Users/sian/Git/slack-help-bot/app.js:452:25
    at async Array.<anonymous> (/Users/sian/Git/slack-help-bot/node_modules/@slack/bolt/dist/middleware/builtin.js:233:9)
    at async Array.onlyEvents (/Users/sian/Git/slack-help-bot/node_modules/@slack/bolt/dist/middleware/builtin.js:63:5)

Potential Fix

Implement a check beforehand to make sure the ticket IDs are not identical

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.