Add support to send files in Slack CLI tool (#39778)

* Add a file upload command to the slack CLI.

* Clean up, add file command to program.

* Rename the command to 'file'

* Better error handling, don't ask for file info.
This commit is contained in:
Sam Seay 2023-08-18 02:06:37 +08:00 committed by GitHub
parent 2afba8b8fe
commit 3e9656187a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 133 additions and 7 deletions

View File

@ -3592,6 +3592,9 @@ importers:
'@octokit/types':
specifier: ^9.2.0
version: 9.2.0
'@slack/web-api':
specifier: ^6.9.0
version: 6.9.0
'@types/cli-table':
specifier: ^0.3.1
version: 0.3.1
@ -12433,8 +12436,8 @@ packages:
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
'@babel/core': 7.21.3
'@jest/types': 29.5.0
'@jridgewell/trace-mapping': 0.3.17
'@jest/types': 29.6.1
'@jridgewell/trace-mapping': 0.3.19
babel-plugin-istanbul: 6.1.1
chalk: 4.1.2
convert-source-map: 2.0.0
@ -12442,7 +12445,7 @@ packages:
graceful-fs: 4.2.9
jest-haste-map: 29.5.0
jest-regex-util: 29.4.3
jest-util: 29.5.0
jest-util: 29.6.2
micromatch: 4.0.5
pirates: 4.0.5
slash: 3.0.0
@ -13917,6 +13920,11 @@ packages:
engines: {node: '>= 12.13.0', npm: '>= 6.12.0'}
dev: false
/@slack/types@2.8.0:
resolution: {integrity: sha512-ghdfZSF0b4NC9ckBA8QnQgC9DJw2ZceDq0BIjjRSv6XAZBXJdWgxIsYz0TYnWSiqsKZGH2ZXbj9jYABZdH3OSQ==}
engines: {node: '>= 12.13.0', npm: '>= 6.12.0'}
dev: false
/@slack/web-api@5.15.0:
resolution: {integrity: sha512-tjQ8Zqv/Fmj9SOL9yIEd7IpTiKfKHi9DKAkfRVeotoX0clMr3SqQtBqO+KZMX27gm7dmgJsQaDKlILyzdCO+IA==}
engines: {node: '>= 8.9.0', npm: '>= 5.5.1'}
@ -13954,6 +13962,25 @@ packages:
- debug
dev: false
/@slack/web-api@6.9.0:
resolution: {integrity: sha512-RME5/F+jvQmZHkoP+ogrDbixq1Ms1mBmylzuWq4sf3f7GCpMPWoiZ+WqWk+sism3vrlveKWIgO9R4Qg9fiRyoQ==}
engines: {node: '>= 12.13.0', npm: '>= 6.12.0'}
dependencies:
'@slack/logger': 3.0.0
'@slack/types': 2.8.0
'@types/is-stream': 1.1.0
'@types/node': 16.18.21
axios: 0.27.2
eventemitter3: 3.1.2
form-data: 2.5.1
is-electron: 2.2.2
is-stream: 1.1.0
p-queue: 6.6.2
p-retry: 4.6.1
transitivePeerDependencies:
- debug
dev: false
/@storybook/addon-a11y@6.5.17-alpha.0(react-dom@17.0.2)(react@17.0.2):
resolution: {integrity: sha512-ZjYxGpuN7/euPscmgQys6QJ+ASVxrFHh28HPd8SqH+j1UmTiGnwPFYmUTm8sY8fMwormdy/H/phQ8FX6xNZ31Q==}
peerDependencies:
@ -21510,6 +21537,15 @@ packages:
- debug
dev: true
/axios@0.27.2:
resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
dependencies:
follow-redirects: 1.15.2(debug@4.3.3)
form-data: 4.0.0
transitivePeerDependencies:
- debug
dev: false
/axobject-query@2.2.0:
resolution: {integrity: sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==}
@ -30405,6 +30441,10 @@ packages:
resolution: {integrity: sha512-SpMppC2XR3YdxSzczXReBjqs2zGscWQpBIKqwXYBFic0ERaxNVgwLCHwOLZeESfdJQjX0RDvrJ1lBXX2ij+G1Q==}
dev: false
/is-electron@2.2.2:
resolution: {integrity: sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg==}
dev: false
/is-extendable@0.1.1:
resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
engines: {node: '>=0.10.0'}
@ -37963,7 +38003,7 @@ packages:
postcss: 8.4.21
schema-utils: 3.1.1
semver: 7.5.0
webpack: 5.70.0(webpack-cli@4.9.2)
webpack: 5.70.0(webpack-cli@3.3.12)
/postcss-loader@4.3.0(postcss@8.4.21)(webpack@5.76.3):
resolution: {integrity: sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==}
@ -41117,7 +41157,7 @@ packages:
sass: 1.60.0
schema-utils: 3.1.1
semver: 7.5.0
webpack: 5.76.3(webpack-cli@3.3.12)
webpack: 5.76.3(webpack-cli@4.9.2)
dev: true
/sass-loader@12.6.0(sass@1.60.0)(webpack@5.76.3):

View File

@ -29,7 +29,8 @@
"promptly": "^3.2.0",
"semver": "^7.3.2",
"simple-git": "^3.10.0",
"uuid": "^9.0.0"
"uuid": "^9.0.0",
"@slack/web-api": "^6.9.0"
},
"devDependencies": {
"@types/jest": "^27.4.1",

View File

@ -7,6 +7,7 @@ import { Command } from '@commander-js/extra-typings';
* Internal dependencies
*/
import { slackMessageCommand } from './slack-message';
import { slackFileCommand } from './slack-file';
/**
* Internal dependencies
@ -14,6 +15,7 @@ import { slackMessageCommand } from './slack-message';
const program = new Command( 'slack' )
.description( 'Slack message sending utilities' )
.addCommand( slackMessageCommand, { isDefault: true } );
.addCommand( slackMessageCommand, { isDefault: true } )
.addCommand( slackFileCommand );
export default program;

View File

@ -0,0 +1,83 @@
/**
* External dependencies
*/
import { Command } from '@commander-js/extra-typings';
import { ErrorCode, WebClient } from '@slack/web-api';
import { basename } from 'path';
/**
* External dependencies
*/
import { existsSync } from 'fs';
/**
* Internal dependencies
*/
import { Logger } from '../../../core/logger';
export const slackFileCommand = new Command( 'file' )
.description( 'Send a file upload message to a slack channel' )
.argument(
'<token>',
'Slack authentication token bearing required scopes.'
)
.argument( '<text>', 'Text based message to send to the slack channel.' )
.argument( '<filePath>', 'File path to upload to the slack channel.' )
.argument(
'<channelIds...>',
'Slack channel IDs to send the message to. Pass as many as you like.'
)
.option(
'--dont-fail',
'Do not fail the command if a message fails to send to any channel.'
)
.action( async ( token, text, filePath, channels, { dontFail } ) => {
Logger.startTask(
`Attempting to send message to Slack for channels: ${ channels.join(
','
) }`
);
const shouldFail = ! dontFail;
if ( filePath && ! existsSync( filePath ) ) {
Logger.error(
`Unable to open file with path: ${ filePath }`,
shouldFail
);
}
const client = new WebClient( token );
for ( const channel of channels ) {
try {
await client.files.uploadV2( {
file: filePath,
filename: basename( filePath ),
channel_id: channel,
initial_comment: text.replace( /\\n/g, '\n' ),
request_file_info: false,
} );
Logger.notice(
`Successfully uploaded ${ filePath } to channel: ${ channel }`
);
} catch ( e ) {
if (
'code' in e &&
e.code === ErrorCode.PlatformError &&
'message' in e &&
e.message.includes( 'missing_scope' )
) {
Logger.error(
`The provided token does not have the required scopes, please add files:write and chat:write to the token.`,
shouldFail
);
} else {
Logger.error( e, shouldFail );
}
}
}
Logger.endTask();
} );