Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a @slack/cli-hooks package that implements Slack CLI hooks #1714

Merged
merged 48 commits into from Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
a6c1ffb
feat: introduce a package for slack cli hooks
zimeg Jan 5, 2024
791d35e
fix: correct errors in hooks package before publishing
zimeg Jan 9, 2024
49e6f3d
feat: convert scripts to typescript for type safety
zimeg Jan 9, 2024
808fba4
chore: bump package version after accidental publish
zimeg Jan 9, 2024
8a889eb
feat: remove a build step but keep typings with jsdoc
zimeg Jan 10, 2024
5827a8c
chore: merge w main
zimeg Jan 10, 2024
e169b70
test: add coverage and fix problems in the scripts
zimeg Jan 10, 2024
63ba992
ci: include the hooks package in automated tests
zimeg Jan 10, 2024
bd4da54
ci: continue running all tests even if one fails
zimeg Jan 10, 2024
cbdfb7d
test: compare error outputs of different node versions
zimeg Jan 10, 2024
938dc24
docs: include instructions for app setup in the readme
zimeg Jan 11, 2024
fb2ee36
chore: merge w main
zimeg Jan 11, 2024
0fbb96e
chore: bump the package version another patch
zimeg Jan 11, 2024
54d05a9
style: improve wording and such semantics
zimeg Jan 11, 2024
81e7a6a
test: update expected output with actual output
zimeg Jan 11, 2024
75d1994
fix: remove script extensions from get-manifest
zimeg Jan 11, 2024
f04d115
docs: switch information about setup for hooks details
zimeg Jan 11, 2024
6866520
refactor: rename this package from hooks to cli-hooks
zimeg Jan 11, 2024
72b0d00
fix: run tests for the newly named package instead
zimeg Jan 11, 2024
c6f3da2
feat: default to an app.js script in the start hook
zimeg Jan 12, 2024
46d7f08
chore: merge w main
zimeg Jan 16, 2024
e8963b1
fix: lookup manifest file across different operating systems
zimeg Jan 23, 2024
02dc946
chore: bump the package patch version
zimeg Jan 23, 2024
a800d5a
refactor: export hook as modules instead of iife scripts
zimeg Jan 24, 2024
a4ba93e
style: remove leftover jsdoc from a testing iteration
zimeg Jan 24, 2024
287b21b
feat: adapt the message boundaries protocol implementation
zimeg Jan 24, 2024
c96858b
feat: remove upgrade checks for the deno sdk
zimeg Jan 25, 2024
af8c9a3
feat: compare package versions with the semver package
zimeg Jan 25, 2024
a4c2cc0
docs: note steps for troubleshooting global installations
zimeg Jan 25, 2024
0e5cf60
chore: include the mit license with this package
zimeg Jan 25, 2024
953588b
chore: bump the package patch version
zimeg Jan 25, 2024
143075a
fix: include semver types for the typescript typechecker
zimeg Jan 25, 2024
3587643
fix: follow script symbolic links to the actual file path
zimeg Jan 25, 2024
26ed497
chore: bump the package patch version
zimeg Jan 25, 2024
7773a9d
fix: include protocols in the packaged bundle
zimeg Jan 25, 2024
d5fd65d
refactor: rename protocol test file to match the implementation
zimeg Jan 25, 2024
9aab3c9
chore: bump the package patch version
zimeg Jan 25, 2024
a6e72d3
fix: log responses with the protocol response
zimeg Jan 26, 2024
cb1c85e
feat: remove extraneous logs from the start hook
zimeg Jan 26, 2024
614a965
chore: bump the package patch version
zimeg Jan 26, 2024
f923d94
test: display coverage after testing results
zimeg Jan 26, 2024
91e139a
fix: use the exported `SUPPORTED_NAMED_PROTOCOLS` in get-hooks
zimeg Jan 26, 2024
9a2b931
test: assert missing boundary error text matches
zimeg Jan 26, 2024
c7ded6e
docs: improve remediation errors for missing start tokens
zimeg Jan 26, 2024
6fe204b
refactor: call the base protocol the default protocol
zimeg Jan 26, 2024
c3b804e
refactor: get the protocol implementation and not an interface
zimeg Jan 26, 2024
980eee0
chore: bump the package patch version
zimeg Jan 26, 2024
ab411ac
chore: release a major version of this package
zimeg Jan 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/ci-build.yml
Expand Up @@ -11,9 +11,18 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
node-version: [18.x, 20.x]
package: [packages/logger, packages/oauth, packages/rtm-api, packages/socket-mode, packages/types, packages/web-api, packages/webhook]
package:
- packages/cli-hooks
- packages/logger
- packages/oauth
- packages/rtm-api
- packages/socket-mode
- packages/types
- packages/web-api
- packages/webhook
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
Expand Down
7 changes: 7 additions & 0 deletions packages/cli-hooks/.c8rc.json
@@ -0,0 +1,7 @@
{
"include": ["src/*.js"],
"exclude": ["**/*.spec.js"],
"reporter": ["lcov", "text"],
"all": false,
"cache": true
}
1 change: 1 addition & 0 deletions packages/cli-hooks/.eslintignore
188 changes: 188 additions & 0 deletions packages/cli-hooks/.eslintrc.cjs
@@ -0,0 +1,188 @@
// SlackAPI JavaScript style
// ---
// This style helps maintainers enforce safe and consistent programming practices in this project. It is not meant to be
// comprehensive on its own or vastly different from existing styles. The goal is to inherit and aggregate as many of
// the communities' recommended styles for the technologies used as we can. When, and only when, we have a stated need
// to differentiate, we add more rules (or modify options). Therefore, the fewer rules directly defined in this file,
// the better.
//
// These styles are a subset of the shared JavaScript and TypeScript configurations to only target JavaScript packages.

module.exports = {
root: true,
parserOptions: {
ecmaVersion: 2022
},

// Ignore all build outputs and artifacts (node_modules, dotfiles, and dot directories are implicitly ignored)
ignorePatterns: [
'/coverage',
],

// These environments contain lists of global variables which are allowed to be accessed
//
// The target node version (v18) supports all needed ES2022 features: https://node.green
env: {
es2022: true,
node: true,
},

extends: [
// ESLint's recommended built-in rules: https://eslint.org/docs/rules/
'eslint:recommended',

// Node plugin's recommended rules: https://github.com/mysticatea/eslint-plugin-node
'plugin:node/recommended',

// AirBnB style guide (without React) rules: https://github.com/airbnb/javascript.
'airbnb-base',

// JSDoc plugin's recommended rules
'plugin:jsdoc/recommended',
],

rules: {
// JavaScript rules
// ---
// The top level of this configuration contains rules which apply to JavaScript.
//
// This section does not contain rules meant to override options or disable rules in the base configurations
// (ESLint, Node, AirBnb). Those rules are added in the final override.

// Eliminate tabs to standardize on spaces for indentation. If you want to use tabs for something other than
// indentation, you may need to turn this rule off using an inline config comments.
'no-tabs': 'error',

// Bans use of comma as an operator because it can obscure side effects and is often an accident.
'no-sequences': 'error',

// Disallow the use of process.exit()
'node/no-process-exit': 'error',

// Allow safe references to functions before the declaration.
'no-use-before-define': ['error', 'nofunc'],

// Allow scripts for hooks implementations.
'node/shebang': 'off',

// Allow unlimited classes in a file.
'max-classes-per-file': 'off',

// Disallow invocations of require(). This will help make imports more consistent and ensures a smoother
// transition to the best future syntax.
'import/no-commonjs': ['error', {
allowConditionalRequire: false,
}],

// Don't verify that all named imports are part of the set of named exports for the referenced module. The
// TypeScript compiler will already perform this check, so it is redundant.
'import/named': 'off',
'node/no-missing-import': 'off',

// Require extensions for imported modules
'import/extensions': ['error', 'ignorePackages', {
'js': 'always',
}],

// Allow use of import and export syntax, despite it not being supported in the node versions. Since this
// project is transpiled, the ignore option is used. Overrides node/recommended.
'node/no-unsupported-features/es-syntax': ['error', { ignores: ['modules'] }],

'operator-linebreak': ['error', 'after', {
overrides: { '=': 'none' }
}],
},

overrides: [
{
files: ['**/*.js'],
rules: {
// Override rules
// ---
// This level of this configuration contains rules which override options or disable rules in the base
// configurations in JavaScript.

// Increase the max line length to 120. The rest of this setting is copied from the AirBnB config.
'max-len': ['error', 120, 2, {
ignoreUrls: true,
ignoreComments: false,
ignoreRegExpLiterals: true,
ignoreStrings: true,
ignoreTemplateLiterals: true,
}],

// Restrict the use of backticks to declare a normal string. Template literals should only be used when the
// template string contains placeholders. The rest of this setting is copied from the AirBnb config.
quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: false }],

// The server side Slack API uses snake_case for parameters often.
//
// For mocking and override support, we need to allow snake_case.
// Allow leading underscores for parameter names, which is used to acknowledge unused variables in TypeScript.
// Also, enforce camelCase naming for variables. Ideally, the leading underscore could be restricted to only
// unused parameter names, but this rule isn't capable of knowing when a variable is unused. The camelcase and
// no-underscore-dangle rules are replaced with the naming-convention rule because this single rule can serve
// both purposes, and it works fine on non-TypeScript code.
camelcase: 'error',
'no-underscore-dangle': 'error',
'no-unused-vars': [
'error',
{
varsIgnorePattern: '^_',
argsIgnorePattern: '^_'
}
],

// Allow cyclical imports. Turning this rule on is mainly a way to manage the performance concern for linting
// time. Our projects are not large enough to warrant this. Overrides AirBnB styles.
'import/no-cycle': 'off',

// Prevent importing submodules of other modules. Using the internal structure of a module exposes
// implementation details that can potentially change in breaking ways. Overrides AirBnB styles.
'import/no-internal-modules': ['error', {
// Use the following option to set a list of allowable globs in this project.
allow: [
'**/middleware/*', // the src/middleware directory doesn't export a module, it's just a namespace.
'**/receivers/*', // the src/receivers directory doesn't export a module, it's just a namespace.
'**/types/**/*',
'**/types/*', // type heirarchies should be used however one wants
],
}],

// Remove the minProperties option for enforcing line breaks between braces. The AirBnB config sets this to 4,
// which is arbitrary and not backed by anything specific in the style guide. If we just remove it, we can
// rely on the max-len rule to determine if the line is too long and then enforce line breaks. Overrides AirBnB
// styles.
'object-curly-newline': ['error', { multiline: true, consistent: true }],
},
},
{
files: ['src/**/*.spec.js'],
rules: {
// Test-specific rules
// ---
// Rules that only apply to JavaScript _test_ source files

// With Mocha as a test framework, it is sometimes helpful to assign
// shared state to Mocha's Context object, for example in setup and
// teardown test methods. Assigning stub/mock objects to the Context
// object via `this` is a common pattern in Mocha. As such, using
// `function` over the the arrow notation binds `this` appropriately and
// should be used in tests. So: we turn off the prefer-arrow-callback
// rule.
// See https://github.com/slackapi/bolt-js/pull/1012#pullrequestreview-711232738
// for a case of arrow-vs-function syntax coming up for the team
'prefer-arrow-callback': 'off',
// Using ununamed functions (e.g., null logger) in tests is fine
'func-names': 'off',
// In tests, don't force constructing a Symbol with a descriptor, as
// it's probably just for tests
'symbol-description': 'off',

'node/no-unpublished-import': ['error', {
"allowModules": ["mocha"],
}],
},
},
],
};
6 changes: 6 additions & 0 deletions packages/cli-hooks/.gitignore
@@ -0,0 +1,6 @@
# Node and NPM stuff
/node_modules
package-lock.json

# Coverage carryover
/coverage
22 changes: 22 additions & 0 deletions packages/cli-hooks/LICENSE
@@ -0,0 +1,22 @@
MIT License

Copyright (c) 2024- Slack Technologies, LLC

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
122 changes: 122 additions & 0 deletions packages/cli-hooks/README.md
@@ -0,0 +1,122 @@
# Slack CLI Hooks

The `@slack/cli-hooks` package contains scripts that implement the contract
between the [Slack CLI][cli] and [Bolt for JavaScript][bolt].

## Overview

This library enables inter-process communication between the Slack CLI and
applications built with Bolt for JavaScript.

When used together, the CLI delegates various tasks to the Bolt application by
invoking processes ("hooks") and then making use of the responses provided by
each hook's `stdout`.

For a complete list of available hooks, read the [Supported Hooks][supported]
section.

## Requirements

This package supports Node v18 and higher. It's highly recommended to use [the
latest LTS version of Node][node].

An updated version of the Slack CLI is also encouraged while using this package.

## Installation

Add this package as a development dependency for your project with the following
command:

```sh
$ npm install --save-dev @slack/cli-hooks
```

Follow [the installation guide][install] to download the Slack CLI and easily
run the scripts included in this package.

## Usage

A Slack CLI-compatible Slack application includes a `slack.json` file that
contains hooks specific to that project. Each hook is associated with commands
that are available in the Slack CLI. By default, `get-hooks` retrieves all of
the [supported hooks][supported] and their corresponding scripts as defined in
this package.

The CLI will try to use the version of the `@slack/cli-hooks` specified in your
application's `package.json`. The hooks in this package are automatically added
to the `./node_modules/.bin` directory of your application when this package is
installed.

### Supported Hooks

The hooks that are currently supported for use within the Slack CLI include
`check-update`, `get-hooks`, `get-manifest`, and `start`:

| Hook Name | CLI Command | File |Description |
| -------------- | ---------------- | ---- | ----------- |
| `check-update` | `slack update` | [`check-update.js`](./src/check-update.js) | Checks the project's Slack dependencies to determine whether or not any packages need to be updated. |
| `get-hooks` | All | [`get-hooks.js`](./src/get-hooks.js) | Fetches the list of available hooks for the CLI from this repository. |
| `get-manifest` | `slack manifest` | [`get-manifest.js`](./src/get-manifest.js) | Converts a `manifest.json` file into a valid manifest JSON payload. |
| `start` | `slack run` | [`start.js`](./src/start.js) | While developing locally, the CLI manages a socket connection with Slack's backend and utilizes this hook for events received via this connection. |

### Overriding Hooks

To customize the behavior of a hook, add the hook to your application's
`slack.json` file and provide a corresponding script to be executed.

When commands are run, the Slack CLI will look to the project's hook definitions
and use those instead of what's defined in this library, if provided. Only
[supported hooks][supported] will be recognized and executed by the Slack CLI.

Below is an example `slack.json` file that overrides the default `start` hook:

```json
{
"hooks": {
"get-hooks": "npx -q --no-install -p @slack/cli-hooks slack-cli-get-hooks",
"start": "npm run dev"
}
}
```

### Troubleshooting

Sometimes the hook scripts are installed globally and might not be automatically
updated. To determine the source of these scripts, check the `node_modules/.bin`
directory of your project then run the following command:

```sh
$ which npx slack-cli-get-hooks # macOS / Linux
```

```cmd
C:\> where.exe npx slack-cli-get-hooks # Windows
```

These hooks can be safely removed and reinstalled at your application directory
to ensure you're using the correct version for your project.

## Getting help

If you get stuck, we're here to help. The following are the best ways to get
assistance working through your issue:

* [Issue Tracker][issues] for questions, feature requests, bug reports and
general discussion related to these packages. Try searching before you create
a new issue.
* [Email us][email]: `developers@slack.com`
* [Community Slack][community]: a Slack community for developers building all
kinds of Slack apps. You can find the maintainers and users of these packages
in **#lang-javascript**.

<!-- a collection of links -->
[bolt]: https://github.com/slackapi/bolt-js
[cli]: https://api.slack.com/automation/cli
[community]: https://community.slack.com/
[config]: https://api.slack.com/apps
[email]: mailto:developers@slack.com
[install]: https://api.slack.com/automation/cli/install
[issues]: http://github.com/slackapi/node-slack-sdk/issues
[manifest]: https://api.slack.com/reference/manifests
[node]: https://github.com/nodejs/Release#release-schedule
[supported]: #supported-hooks