diff --git a/CHANGELOG.md b/CHANGELOG.md index 62ab8e3a21..672fa607c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [7.29.0](https://github.com/heroku/cli/compare/v7.28.0...v7.29.0) (2019-08-21) + + +### Features + +* **webhooks:** add oclif version of webhooks plugin ([#1253](https://github.com/heroku/cli/issues/1253)) ([110c516](https://github.com/heroku/cli/commit/110c516)) + + + + + # [7.28.0](https://github.com/heroku/cli/compare/v7.27.1...v7.28.0) (2019-08-19) diff --git a/docs/local.md b/docs/local.md index 5137911403..cb08688f6a 100644 --- a/docs/local.md +++ b/docs/local.md @@ -33,7 +33,7 @@ EXAMPLE $ heroku local web=1,worker=2 ``` -_See code: [@heroku-cli/plugin-local](https://github.com/heroku/cli/blob/v7.26.2/src/commands/local/index.ts)_ +_See code: [@heroku-cli/plugin-local](https://github.com/heroku/cli/blob/v7.28.0/src/commands/local/index.ts)_ ## `heroku local:run` @@ -51,7 +51,7 @@ EXAMPLE $ heroku local:run bin/migrate ``` -_See code: [@heroku-cli/plugin-local](https://github.com/heroku/cli/blob/v7.26.2/src/commands/local/run.ts)_ +_See code: [@heroku-cli/plugin-local](https://github.com/heroku/cli/blob/v7.28.0/src/commands/local/run.ts)_ ## `heroku local:version` @@ -62,4 +62,4 @@ USAGE $ heroku local:version ``` -_See code: [@heroku-cli/plugin-local](https://github.com/heroku/cli/blob/v7.26.2/src/commands/local/version.ts)_ +_See code: [@heroku-cli/plugin-local](https://github.com/heroku/cli/blob/v7.28.0/src/commands/local/version.ts)_ diff --git a/docs/reviewapps.md b/docs/reviewapps.md index 1db56d98ee..c151a0643f 100644 --- a/docs/reviewapps.md +++ b/docs/reviewapps.md @@ -25,7 +25,7 @@ EXAMPLE $ heroku reviewapps:disable -p mypipeline -a myapp --autodeploy ``` -_See code: [@heroku-cli/plugin-pipelines](https://github.com/heroku/heroku-cli-plugin-pipelines/blob/v7.27.0/src/commands/reviewapps/disable.ts)_ +_See code: [@heroku-cli/plugin-pipelines](https://github.com/heroku/heroku-cli-plugin-pipelines/blob/v7.28.0/src/commands/reviewapps/disable.ts)_ ## `heroku reviewapps:enable` @@ -45,4 +45,4 @@ EXAMPLE $ heroku reviewapps:enable -p mypipeline -a myapp --autodeploy --autodestroy ``` -_See code: [@heroku-cli/plugin-pipelines](https://github.com/heroku/heroku-cli-plugin-pipelines/blob/v7.27.0/src/commands/reviewapps/enable.ts)_ +_See code: [@heroku-cli/plugin-pipelines](https://github.com/heroku/heroku-cli-plugin-pipelines/blob/v7.28.0/src/commands/reviewapps/enable.ts)_ diff --git a/lerna.json b/lerna.json index 0a33f105d4..3e4ed1280c 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "7.28.0", + "version": "7.29.0", "lerna": "2.11.0", "useWorkspaces": true, "npmClient": "yarn", diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 62ab8e3a21..672fa607c4 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [7.29.0](https://github.com/heroku/cli/compare/v7.28.0...v7.29.0) (2019-08-21) + + +### Features + +* **webhooks:** add oclif version of webhooks plugin ([#1253](https://github.com/heroku/cli/issues/1253)) ([110c516](https://github.com/heroku/cli/commit/110c516)) + + + + + # [7.28.0](https://github.com/heroku/cli/compare/v7.27.1...v7.28.0) (2019-08-19) diff --git a/packages/cli/README.md b/packages/cli/README.md index 3c610b4239..54f0fd0a7e 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -77,7 +77,6 @@ For other issues, [submit a support ticket](https://help.heroku.com/). * [`heroku status`](docs/status.md) - status of the Heroku platform * [`heroku teams`](docs/teams.md) - manage teams * [`heroku update`](docs/update.md) - update the Heroku CLI -* [`heroku webhooks`](docs/webhooks.md) - setup HTTP notifications of app activity diff --git a/packages/cli/package.json b/packages/cli/package.json index 21e461ad74..3115f7386a 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "heroku", "description": "CLI to interact with Heroku", - "version": "7.28.0", + "version": "7.29.0", "author": "Jeff Dickey @jdxcode", "bin": { "heroku": "./bin/run" @@ -34,7 +34,7 @@ "@heroku-cli/plugin-run-v5": "^7.24.0", "@heroku-cli/plugin-spaces": "^7.27.0", "@heroku-cli/plugin-status": "^7.24.0", - "@heroku-cli/plugin-webhooks-v5": "^7.24.0", + "@heroku-cli/plugin-webhooks": "^7.29.0", "@oclif/command": "1.5.18", "@oclif/config": "1.13.2", "@oclif/errors": "1.2.2", @@ -130,7 +130,7 @@ "@heroku-cli/plugin-run-v5", "@heroku-cli/plugin-spaces", "@heroku-cli/plugin-status", - "@heroku-cli/plugin-webhooks-v5", + "@heroku-cli/plugin-webhooks", "@oclif/plugin-commands", "@oclif/plugin-help", "@oclif/plugin-not-found", diff --git a/packages/webhooks-v5/.gitignore b/packages/webhooks-v5/.gitignore deleted file mode 100644 index 16d4f51201..0000000000 --- a/packages/webhooks-v5/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.nyc_output -node_modules diff --git a/packages/webhooks-v5/CHANGELOG.md b/packages/webhooks-v5/CHANGELOG.md deleted file mode 100644 index dc369b15d5..0000000000 --- a/packages/webhooks-v5/CHANGELOG.md +++ /dev/null @@ -1,290 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -# [7.24.0](https://github.com/heroku/cli/compare/v7.23.0...v7.24.0) (2019-04-25) - -**Note:** Version bump only for package @heroku-cli/plugin-webhooks-v5 - - - - - -## [7.22.7](https://github.com/heroku/cli/compare/v7.22.6...v7.22.7) (2019-03-14) - -**Note:** Version bump only for package @heroku-cli/plugin-webhooks-v5 - - - - - -## [7.22.6](https://github.com/heroku/cli/compare/v7.22.5...v7.22.6) (2019-03-14) - -**Note:** Version bump only for package @heroku-cli/plugin-webhooks-v5 - - - - - -## [7.22.5](https://github.com/heroku/cli/compare/v7.22.4...v7.22.5) (2019-03-13) - -**Note:** Version bump only for package @heroku-cli/plugin-webhooks-v5 - - - - - -## [7.22.4](https://github.com/heroku/cli/compare/v7.22.3...v7.22.4) (2019-03-06) - -**Note:** Version bump only for package @heroku-cli/plugin-webhooks-v5 - - - - - -# [7.21.0](https://github.com/heroku/cli/compare/v7.20.1...v7.21.0) (2019-02-11) - -**Note:** Version bump only for package @heroku-cli/plugin-webhooks-v5 - - - - - -# [7.20.0](https://github.com/heroku/cli/compare/v7.19.4...v7.20.0) (2019-02-05) - - -### Bug Fixes - -* increase mocha timeouts ([7d31bc1](https://github.com/heroku/cli/commit/7d31bc1)) - - - - - -## [7.19.4](https://github.com/heroku/cli/compare/v7.19.3...v7.19.4) (2018-12-19) - - -### Bug Fixes - -* upgrade dependencies ([f1b3886](https://github.com/heroku/cli/commit/f1b3886)) - - - - - -## [7.19.3](https://github.com/heroku/cli/compare/v7.19.2...v7.19.3) (2018-12-04) - - -### Bug Fixes - -* remove login warnings ([39d8c47](https://github.com/heroku/cli/commit/39d8c47)) - - - - - -# [7.19.0](https://github.com/heroku/cli/compare/v7.18.10...v7.19.0) (2018-12-03) - - -### Bug Fixes - -* updated command ([1c49051](https://github.com/heroku/cli/commit/1c49051)) - - - - - -## [7.18.10](https://github.com/heroku/cli/compare/v7.18.9...v7.18.10) (2018-11-26) - - -### Bug Fixes - -* updated deps ([576c85a](https://github.com/heroku/cli/commit/576c85a)) - - - - - -## [7.18.9](https://github.com/heroku/cli/compare/v7.18.8...v7.18.9) (2018-11-15) - -**Note:** Version bump only for package @heroku-cli/plugin-webhooks-v5 - - - - - - -## [7.18.8](https://github.com/heroku/cli/compare/v7.18.7...v7.18.8) (2018-11-14) - - -### Bug Fixes - -* **webhooks-v5:** add remote flag ([#1136](https://github.com/heroku/cli/issues/1136)) ([eede7a9](https://github.com/heroku/cli/commit/eede7a9)) - - - - - -## [7.16.2](https://github.com/heroku/cli/compare/v7.16.1...v7.16.2) (2018-10-02) - - -### Bug Fixes - -* updated deps ([482dc85](https://github.com/heroku/cli/commit/482dc85)) - - - - - - -# [7.16.0](https://github.com/heroku/cli/compare/v7.15.2...v7.16.0) (2018-09-14) - - -### Bug Fixes - -* updated deps ([6d3be5a](https://github.com/heroku/cli/commit/6d3be5a)) -* updated dev-cli ([022396b](https://github.com/heroku/cli/commit/022396b)) - - - - - - -# [7.15.0](https://github.com/heroku/cli/compare/v7.14.4...v7.15.0) (2018-09-10) - -**Note:** Version bump only for package @heroku-cli/plugin-webhooks-v5 - - - - - - -## [7.12.6](https://github.com/heroku/cli/compare/v7.12.5...v7.12.6) (2018-08-30) - - -### Bug Fixes - -* windows test failures ([5b4d171](https://github.com/heroku/cli/commit/5b4d171)) - - - - - - -## [7.12.4](https://github.com/heroku/cli/compare/v7.12.3...v7.12.4) (2018-08-29) - -**Note:** Version bump only for package @heroku-cli/plugin-webhooks-v5 - - - - - - -## [7.9.3](https://github.com/heroku/cli/compare/v7.9.2...v7.9.3) (2018-08-18) - -**Note:** Version bump only for package @heroku-cli/plugin-webhooks-v5 - - - - - - -## [7.9.2](https://github.com/heroku/cli/compare/v7.9.1...v7.9.2) (2018-08-18) - - -### Bug Fixes - -* typescript 3.0 ([268c0af](https://github.com/heroku/cli/commit/268c0af)) - - - - - - -## [7.9.1](https://github.com/heroku/cli/compare/v7.9.0...v7.9.1) (2018-08-17) - - -### Bug Fixes - -* updated some dependencies ([0306f88](https://github.com/heroku/cli/commit/0306f88)) - - - - - -## [7.5.6](https://github.com/heroku/cli/compare/v7.5.5...v7.5.6) (2018-06-29) - - -### Bug Fixes - -* bump legacy and color ([a3fa970](https://github.com/heroku/cli/commit/a3fa970)) - - - - - -## [7.5.5](https://github.com/heroku/cli/compare/v7.5.4...v7.5.5) (2018-06-29) - - - - -**Note:** Version bump only for package @heroku-cli/plugin-webhooks-v5 - - -## [7.5.1](https://github.com/heroku/cli/compare/v7.5.0...v7.5.1) (2018-06-26) - - -### Bug Fixes - -* bump dev-cli ([fb3e41a](https://github.com/heroku/cli/commit/fb3e41a)) - - - - - -# [7.5.0](https://github.com/heroku/cli/compare/v7.4.11...v7.5.0) (2018-06-26) - - - - -**Note:** Version bump only for package @heroku-cli/plugin-webhooks-v5 - - -## [7.4.8](https://github.com/heroku/cli/compare/v7.4.7...v7.4.8) (2018-06-21) - - - - -**Note:** Version bump only for package @heroku-cli/plugin-webhooks-v5 - - -## [7.4.6](https://github.com/heroku/cli/compare/v7.4.5...v7.4.6) (2018-06-20) - - -### Bug Fixes - -* update dev-cli readme generation ([42a77bc](https://github.com/heroku/cli/commit/42a77bc)) - - - - - -## [7.4.5](https://github.com/heroku/cli/compare/v7.4.4...v7.4.5) (2018-06-20) - - -### Bug Fixes - -* updated monorepo documentation urls ([4bb6fe0](https://github.com/heroku/cli/commit/4bb6fe0)) - - - - - -# [7.4.0](https://github.com/heroku/cli/compare/v7.3.0...v7.4.0) (2018-06-19) - - -### Bug Fixes - -* **webhooks:** rename webhook-type to fix lint issue ([52ecf1a](https://github.com/heroku/cli/commit/52ecf1a)) -* repo name ([c306c78](https://github.com/heroku/cli/commit/c306c78)) diff --git a/packages/webhooks-v5/README.md b/packages/webhooks-v5/README.md deleted file mode 100644 index 0e5611714d..0000000000 --- a/packages/webhooks-v5/README.md +++ /dev/null @@ -1,190 +0,0 @@ -# heroku-webhooks - - -* [`@heroku-cli/plugin-webhooks-v5 webhooks`](#heroku-cliplugin-webhooks-v5-webhooks) -* [`@heroku-cli/plugin-webhooks-v5 webhooks:add`](#heroku-cliplugin-webhooks-v5-webhooksadd) -* [`@heroku-cli/plugin-webhooks-v5 webhooks:deliveries`](#heroku-cliplugin-webhooks-v5-webhooksdeliveries) -* [`@heroku-cli/plugin-webhooks-v5 webhooks:deliveries:info [ID]`](#heroku-cliplugin-webhooks-v5-webhooksdeliveriesinfo-id) -* [`@heroku-cli/plugin-webhooks-v5 webhooks:events`](#heroku-cliplugin-webhooks-v5-webhooksevents) -* [`@heroku-cli/plugin-webhooks-v5 webhooks:events:info [ID]`](#heroku-cliplugin-webhooks-v5-webhookseventsinfo-id) -* [`@heroku-cli/plugin-webhooks-v5 webhooks:info [ID]`](#heroku-cliplugin-webhooks-v5-webhooksinfo-id) -* [`@heroku-cli/plugin-webhooks-v5 webhooks:remove [ID]`](#heroku-cliplugin-webhooks-v5-webhooksremove-id) -* [`@heroku-cli/plugin-webhooks-v5 webhooks:update [ID]`](#heroku-cliplugin-webhooks-v5-webhooksupdate-id) - -## `@heroku-cli/plugin-webhooks-v5 webhooks` - -list webhooks on an app - -``` -USAGE - $ @heroku-cli/plugin-webhooks-v5 webhooks - -OPTIONS - -a, --app=app app to run command against - -r, --remote=remote git remote of app to use - -EXAMPLE - $ heroku webhooks -``` - -_See code: [commands/webhooks/index.js](https://github.com/heroku/cli/blob/v7.24.0/packages/webhooks-v5/commands/webhooks/index.js)_ - -## `@heroku-cli/plugin-webhooks-v5 webhooks:add` - -add a webhook to an app - -``` -USAGE - $ @heroku-cli/plugin-webhooks-v5 webhooks:add - -OPTIONS - -a, --app=app app to run command against - -i, --include=include (required) comma delimited event types your server will receive - -l, --level=level (required) notify does not retry, sync will retry until successful or timeout - -r, --remote=remote git remote of app to use - -s, --secret=secret value to sign delivery with in Heroku-Webhook-Hmac-SHA256 header - -t, --authorization=authorization authoriation header to send with webhooks - -u, --url=url (required) URL for receiver - -EXAMPLE - $ heroku webhooks:add -i api:dyno -l notify -u https://example.com/hooks -``` - -_See code: [commands/webhooks/add.js](https://github.com/heroku/cli/blob/v7.24.0/packages/webhooks-v5/commands/webhooks/add.js)_ - -## `@heroku-cli/plugin-webhooks-v5 webhooks:deliveries` - -list webhook deliveries on an app - -``` -USAGE - $ @heroku-cli/plugin-webhooks-v5 webhooks:deliveries - -OPTIONS - -a, --app=app app to run command against - -r, --remote=remote git remote of app to use - -s, --status=status filter deliveries by status - -EXAMPLE - $ heroku webhooks:deliveries -``` - -_See code: [commands/webhooks/deliveries/index.js](https://github.com/heroku/cli/blob/v7.24.0/packages/webhooks-v5/commands/webhooks/deliveries/index.js)_ - -## `@heroku-cli/plugin-webhooks-v5 webhooks:deliveries:info [ID]` - -info for a webhook event on an app - -``` -USAGE - $ @heroku-cli/plugin-webhooks-v5 webhooks:deliveries:info [ID] - -OPTIONS - -a, --app=app app to run command against - -r, --remote=remote git remote of app to use - -EXAMPLE - $ heroku webhooks:deliveries:info 99999999-9999-9999-9999-999999999999 -``` - -_See code: [commands/webhooks/deliveries/info.js](https://github.com/heroku/cli/blob/v7.24.0/packages/webhooks-v5/commands/webhooks/deliveries/info.js)_ - -## `@heroku-cli/plugin-webhooks-v5 webhooks:events` - -list webhook events on an app - -``` -USAGE - $ @heroku-cli/plugin-webhooks-v5 webhooks:events - -OPTIONS - -a, --app=app app to run command against - -r, --remote=remote git remote of app to use - -EXAMPLE - $ heroku webhooks:events -``` - -_See code: [commands/webhooks/events/index.js](https://github.com/heroku/cli/blob/v7.24.0/packages/webhooks-v5/commands/webhooks/events/index.js)_ - -## `@heroku-cli/plugin-webhooks-v5 webhooks:events:info [ID]` - -info for a webhook event on an app - -``` -USAGE - $ @heroku-cli/plugin-webhooks-v5 webhooks:events:info [ID] - -OPTIONS - -a, --app=app app to run command against - -r, --remote=remote git remote of app to use - -EXAMPLE - $ heroku webhooks:events:info 99999999-9999-9999-9999-999999999999 -``` - -_See code: [commands/webhooks/events/info.js](https://github.com/heroku/cli/blob/v7.24.0/packages/webhooks-v5/commands/webhooks/events/info.js)_ - -## `@heroku-cli/plugin-webhooks-v5 webhooks:info [ID]` - -info for a webhook on an app - -``` -USAGE - $ @heroku-cli/plugin-webhooks-v5 webhooks:info [ID] - -OPTIONS - -a, --app=app app to run command against - -r, --remote=remote git remote of app to use - -EXAMPLE - $ heroku webhooks:info 99999999-9999-9999-9999-999999999999 -``` - -_See code: [commands/webhooks/info.js](https://github.com/heroku/cli/blob/v7.24.0/packages/webhooks-v5/commands/webhooks/info.js)_ - -## `@heroku-cli/plugin-webhooks-v5 webhooks:remove [ID]` - -removes a webhook from an app - -``` -USAGE - $ @heroku-cli/plugin-webhooks-v5 webhooks:remove [ID] - -ARGUMENTS - ID id of webhook to remove - -OPTIONS - -a, --app=app app to run command against - -r, --remote=remote git remote of app to use - -EXAMPLE - $ heroku webhooks:remove 99999999-9999-9999-9999-999999999999 -``` - -_See code: [commands/webhooks/remove.js](https://github.com/heroku/cli/blob/v7.24.0/packages/webhooks-v5/commands/webhooks/remove.js)_ - -## `@heroku-cli/plugin-webhooks-v5 webhooks:update [ID]` - -updates a webhook in an app - -``` -USAGE - $ @heroku-cli/plugin-webhooks-v5 webhooks:update [ID] - -OPTIONS - -a, --app=app app to run command against - -i, --include=include (required) comma delimited event types your server will receive - -l, --level=level (required) notify does not retry, sync will retry until successful or timeout - -r, --remote=remote git remote of app to use - -s, --secret=secret value to sign delivery with in Heroku-Webhook-Hmac-SHA256 header - -t, --authorization=authorization authoriation header to send with webhooks - -u, --url=url (required) URL for receiver - -EXAMPLE - $ heroku webhooks:update 99999999-9999-9999-9999-999999999999 -i dyno -l notify -s - 09928c40bf1b191b645174a19f7053d16a180da37332e719ef0998f4c0a2 -u https://example.com/hooks -``` - -_See code: [commands/webhooks/update.js](https://github.com/heroku/cli/blob/v7.24.0/packages/webhooks-v5/commands/webhooks/update.js)_ - diff --git a/packages/webhooks-v5/circle.yml b/packages/webhooks-v5/circle.yml deleted file mode 100644 index cc29b0c09a..0000000000 --- a/packages/webhooks-v5/circle.yml +++ /dev/null @@ -1,3 +0,0 @@ -machine: - node: - version: 7.10.0 diff --git a/packages/webhooks-v5/commands/webhooks/add.js b/packages/webhooks-v5/commands/webhooks/add.js deleted file mode 100644 index 21177ae840..0000000000 --- a/packages/webhooks-v5/commands/webhooks/add.js +++ /dev/null @@ -1,50 +0,0 @@ -const { Command, flags } = require('@heroku-cli/command') -const cli = require('heroku-cli-util') -const webhookType = require('../../lib/webhook-type.js') - -class Add extends Command { - async run () { - const { flags } = this.parse(Add) - let { path, display } = webhookType(flags) - - let secret = await cli.action(`Adding webhook to ${display}`, new Promise(async resolve => { - let { response } = await this.heroku.post(`${path}/webhooks`, { - headers: { Accept: 'application/vnd.heroku+json; version=3.webhooks' }, - body: { - include: flags.include.split(',').map(s => s.trim()), - level: flags.level, - secret: flags.secret, - url: flags.url, - authorization: flags.authorization - } - }) - let secret - if (response.headers) secret = response.headers['heroku-webhook-secret'] - resolve(secret) - })) - - if (secret) { - cli.styledHeader('Webhooks Signing Secret') - cli.log(secret) - } - } -} - -Add.description = 'add a webhook to an app' - -Add.examples = [ - '$ heroku webhooks:add -i api:dyno -l notify -u https://example.com/hooks' -] - -Add.flags = { - app: flags.app(), - remote: flags.remote(), - pipeline: flags.string({ char: 'p', description: 'pipeline on which to list', hidden: true }), - include: flags.string({ char: 'i', description: 'comma delimited event types your server will receive ', required: true }), - level: flags.string({ char: 'l', description: 'notify does not retry, sync will retry until successful or timeout', required: true }), - secret: flags.string({ char: 's', description: 'value to sign delivery with in Heroku-Webhook-Hmac-SHA256 header' }), - authorization: flags.string({ char: 't', description: 'authoriation header to send with webhooks' }), - url: flags.string({ char: 'u', description: 'URL for receiver', required: true }) -} - -module.exports = Add diff --git a/packages/webhooks-v5/commands/webhooks/deliveries/index.js b/packages/webhooks-v5/commands/webhooks/deliveries/index.js deleted file mode 100644 index 6f6a6b67b9..0000000000 --- a/packages/webhooks-v5/commands/webhooks/deliveries/index.js +++ /dev/null @@ -1,67 +0,0 @@ -const { Command, flags } = require('@heroku-cli/command') -const cli = require('heroku-cli-util') -const webhookType = require('../../../lib/webhook-type.js') - -class Deliveries extends Command { - async run () { - const { flags } = this.parse(Deliveries) - let { path, display } = webhookType(flags) - let max = 1000 - - path = `${path}/webhook-deliveries` - if (flags.status) { - path += `?eq[status]=${encodeURIComponent(flags.status)}` - } - - let { body } = await this.heroku.get(path, { - headers: { - Accept: 'application/vnd.heroku+json; version=3.webhooks', - Range: `seq ..; order=desc,max=${max}` - }, - partial: true - }) - let deliveries = body - - if (deliveries.length === 0) { - cli.log(`${display} has no deliveries`) - } else { - let code = w => { - return (w.last_attempt && w.last_attempt.code && String(w.last_attempt.code)) || '' - } - - deliveries.reverse() - - if (deliveries.length === max) { - cli.error(`Only showing the ${max} most recent deliveries`) - cli.error('It is possible to filter deliveries by using the --status flag') - } - - cli.table(deliveries, { columns: [ - { key: 'id', label: 'Delivery ID' }, - { key: 'created_at', label: 'Created', get: w => w.created_at }, - { key: 'status', label: 'Status', get: w => w.status }, - { key: 'include', label: 'Include', get: w => w.event.include }, - { key: 'level', label: 'Level', get: w => w.webhook.level }, - { key: 'num_attempts', label: 'Attempts', get: w => String(w.num_attempts) }, - { key: 'last_code', label: 'Code', get: code }, - { key: 'last_error', label: 'Error', get: w => (w.last_attempt && w.last_attempt.error_class) || '' }, - { key: 'next_attempt_at', label: 'Next Attempt', get: w => w.next_attempt_at || '' } - ] }) - } - } -} - -Deliveries.description = 'list webhook deliveries on an app' - -Deliveries.examples = [ - '$ heroku webhooks:deliveries' -] - -Deliveries.flags = { - app: flags.app(), - remote: flags.remote(), - status: flags.string({ char: 's', description: 'filter deliveries by status' }), - pipeline: flags.string({ char: 'p', description: 'pipeline on which to list', hidden: true }) -} - -module.exports = Deliveries diff --git a/packages/webhooks-v5/commands/webhooks/deliveries/info.js b/packages/webhooks-v5/commands/webhooks/deliveries/info.js deleted file mode 100644 index d0ae7d159a..0000000000 --- a/packages/webhooks-v5/commands/webhooks/deliveries/info.js +++ /dev/null @@ -1,57 +0,0 @@ -const { Command, flags } = require('@heroku-cli/command') -const cli = require('heroku-cli-util') -const webhookType = require('../../../lib/webhook-type.js') - -class Info extends Command { - async run () { - const { flags, args } = this.parse(Info) - let { path } = webhookType(flags) - - let { body } = await this.heroku.get(`${path}/webhook-deliveries/${args.id}`, { - headers: { Accept: 'application/vnd.heroku+json; version=3.webhooks' } - }) - let delivery = body - - let res = await this.heroku.get(`${path}/webhook-events/${delivery.event.id}`, { - headers: { Accept: 'application/vnd.heroku+json; version=3.webhooks' } - }) - let event = res.body - - let obj = { - Created: delivery.created_at, - Event: delivery.event.id, - Webhook: delivery.webhook.id, - Status: delivery.status, - Include: delivery.event.include, - Level: delivery.webhook.level, - Attempts: delivery.num_attempts, - Code: delivery.last_attempt && delivery.last_attempt.code, - Error: delivery.last_attempt && delivery.last_attempt.error_class, - 'Next Attempt': delivery.next_attempt_at - } - - cli.styledHeader(delivery.id) - cli.styledObject(obj) - - cli.styledHeader('Event Payload') - cli.styledJSON(event.payload) - } -} - -Info.description = 'info for a webhook event on an app' - -Info.examples = [ - '$ heroku webhooks:deliveries:info 99999999-9999-9999-9999-999999999999' -] - -Info.args = [ - { name: 'id' } -] - -Info.flags = { - app: flags.app(), - remote: flags.remote(), - pipeline: flags.string({ char: 'p', description: 'pipeline on which to list', hidden: true }) -} - -module.exports = Info diff --git a/packages/webhooks-v5/commands/webhooks/events/index.js b/packages/webhooks-v5/commands/webhooks/events/index.js deleted file mode 100644 index eb9f8c1ae6..0000000000 --- a/packages/webhooks-v5/commands/webhooks/events/index.js +++ /dev/null @@ -1,43 +0,0 @@ -const { Command, flags } = require('@heroku-cli/command') -const cli = require('heroku-cli-util') -const webhookType = require('../../../lib/webhook-type.js') - -class Events extends Command { - async run () { - const { flags } = this.parse(Events) - cli.warn('heroku webhooks:event is deprecated, please use heroku webhooks:deliveries') - let { path, display } = webhookType(flags) - - let { body } = await this.heroku.get(`${path}/webhook-events`, { - headers: { Accept: 'application/vnd.heroku+json; version=3.webhooks' } - }) - let events = body - - if (events.length === 0) { - cli.log(`${display} has no events`) - } else { - events.sort((a, b) => Date.parse(a.created_at) - Date.parse(b.created_at)) - - cli.table(events, { columns: [ - { key: 'id', label: 'Event ID' }, - { key: 'resource', label: 'Resource', get: w => w.payload.resource }, - { key: 'action', label: 'Action', get: w => w.payload.action }, - { key: 'published_at', label: 'Published At', get: w => w.payload.published_at } - ] }) - } - } -} - -Events.description = 'list webhook events on an app' - -Events.examples = [ - '$ heroku webhooks:events' -] - -Events.flags = { - app: flags.app(), - remote: flags.remote(), - pipeline: flags.string({ char: 'p', description: 'pipeline on which to list', hidden: true }) -} - -module.exports = Events diff --git a/packages/webhooks-v5/commands/webhooks/events/info.js b/packages/webhooks-v5/commands/webhooks/events/info.js deleted file mode 100644 index e8df122f6c..0000000000 --- a/packages/webhooks-v5/commands/webhooks/events/info.js +++ /dev/null @@ -1,41 +0,0 @@ -const { Command, flags } = require('@heroku-cli/command') -const cli = require('heroku-cli-util') -const webhookType = require('../../../lib/webhook-type.js') - -class Info extends Command { - async run () { - const { flags, args } = this.parse(Info) - cli.warn('heroku webhooks:event:info is deprecated, please use heroku webhooks:deliveries:info') - let { path } = webhookType(flags) - - let { body } = await this.heroku.get(`${path}/webhook-events/${args.id}`, { - headers: { Accept: 'application/vnd.heroku+json; version=3.webhooks' } - }) - let webhookEvent = body - - let obj = { - payload: JSON.stringify(webhookEvent.payload, null, 2) - } - - cli.styledHeader(webhookEvent.id) - cli.styledObject(obj) - } -} - -Info.description = 'info for a webhook event on an app' - -Info.examples = [ - '$ heroku webhooks:events:info 99999999-9999-9999-9999-999999999999' -] - -Info.flags = { - app: flags.app(), - remote: flags.remote(), - pipeline: flags.string({ char: 'p', description: 'pipeline on which to list', hidden: true }) -} - -Info.args = [ - { name: 'id' } -] - -module.exports = Info diff --git a/packages/webhooks-v5/commands/webhooks/index.js b/packages/webhooks-v5/commands/webhooks/index.js deleted file mode 100644 index 455e279199..0000000000 --- a/packages/webhooks-v5/commands/webhooks/index.js +++ /dev/null @@ -1,43 +0,0 @@ -const { Command, flags } = require('@heroku-cli/command') -const cli = require('heroku-cli-util') -const webhookType = require('../../lib/webhook-type.js') - -class Webhooks extends Command { - async run () { - const { flags } = this.parse(Webhooks) - let { path, display } = webhookType(flags) - - let { body } = await this.heroku.get(`${path}/webhooks`, { - headers: { Accept: 'application/vnd.heroku+json; version=3.webhooks' } - }) - let webhooks = body - - if (webhooks.length === 0) { - cli.log(`${display} has no webhooks\nUse ${cli.color.cmd('heroku webhooks:add')} to add one.`) - return - } - - webhooks.sort((a, b) => Date.parse(a.created_at) - Date.parse(b.created_at)) - - cli.table(webhooks, { columns: [ - { key: 'id', label: 'Webhook ID' }, - { key: 'url', label: 'URL' }, - { key: 'include', label: 'Include' }, - { key: 'level', label: 'Level' } - ] }) - } -} - -Webhooks.description = 'list webhooks on an app' - -Webhooks.examples = [ - '$ heroku webhooks' -] - -Webhooks.flags = { - app: flags.app(), - remote: flags.remote(), - pipeline: flags.string({ char: 'p', description: 'pipeline on which to list', hidden: true }) -} - -module.exports = Webhooks diff --git a/packages/webhooks-v5/commands/webhooks/info.js b/packages/webhooks-v5/commands/webhooks/info.js deleted file mode 100644 index 041f351ada..0000000000 --- a/packages/webhooks-v5/commands/webhooks/info.js +++ /dev/null @@ -1,43 +0,0 @@ -const { Command, flags } = require('@heroku-cli/command') -const cli = require('heroku-cli-util') -const webhookType = require('../../lib/webhook-type.js') - -class Info extends Command { - async run () { - const { flags, args } = this.parse(Info) - let { path } = webhookType(flags) - - let { body } = await this.heroku.get(`${path}/webhooks/${args.id}`, { - headers: { Accept: 'application/vnd.heroku+json; version=3.webhooks' } - }) - let webhook = body - - let obj = { - 'Webhook ID': webhook.id, - URL: webhook.url, - Include: webhook.include.join(','), - Level: webhook.level - } - - cli.styledHeader(webhook.id) - cli.styledObject(obj) - } -} - -Info.description = 'info for a webhook on an app' - -Info.examples = [ - '$ heroku webhooks:info 99999999-9999-9999-9999-999999999999' -] - -Info.flags = { - app: flags.app(), - remote: flags.remote(), - pipeline: flags.string({ char: 'p', description: 'pipeline on which to list', hidden: true }) -} - -Info.args = [ - { name: 'id' } -] - -module.exports = Info diff --git a/packages/webhooks-v5/commands/webhooks/remove.js b/packages/webhooks-v5/commands/webhooks/remove.js deleted file mode 100644 index 815c462ff1..0000000000 --- a/packages/webhooks-v5/commands/webhooks/remove.js +++ /dev/null @@ -1,33 +0,0 @@ -const { Command, flags } = require('@heroku-cli/command') -const cli = require('heroku-cli-util') -const webhookType = require('../../lib/webhook-type.js') - -class Remove extends Command { - async run () { - const { flags, args } = this.parse(Remove) - let { path, display } = webhookType(flags) - await cli.action(`Removing webhook ${args.id} from ${display}`, {}, - this.heroku.delete(`${path}/webhooks/${args.id}`, { - headers: { Accept: 'application/vnd.heroku+json; version=3.webhooks' } - } - )) - } -} - -Remove.description = 'removes a webhook from an app' - -Remove.examples = [ - '$ heroku webhooks:remove 99999999-9999-9999-9999-999999999999' -] - -Remove.flags = { - app: flags.app(), - remote: flags.remote(), - pipeline: flags.string({ char: 'p', description: 'pipeline on which to list', hidden: true }) -} - -Remove.args = [ - { name: 'id', description: 'id of webhook to remove' } -] - -module.exports = Remove diff --git a/packages/webhooks-v5/commands/webhooks/update.js b/packages/webhooks-v5/commands/webhooks/update.js deleted file mode 100644 index 1a329970f3..0000000000 --- a/packages/webhooks-v5/commands/webhooks/update.js +++ /dev/null @@ -1,89 +0,0 @@ -const { Command, flags } = require('@heroku-cli/command') -const cli = require('heroku-cli-util') -const webhookType = require('../../lib/webhook-type.js') - -class Update extends Command { - async run () { - const { flags, args } = this.parse(Update) - let { path, display } = webhookType(flags) - await cli.action(`Updating webhook ${args.id} for ${display}`, {}, - this.heroku.patch(`${path}/webhooks/${args.id}`, { - headers: { Accept: 'application/vnd.heroku+json; version=3.webhooks' }, - body: { - include: flags.include && flags.include.split(',').map(s => s.trim()), - level: flags.level, - secret: flags.secret, - url: flags.url - } - }) - ) - } -} - -Update.description = 'updates a webhook in an app' - -Update.examples = [ - '$ heroku webhooks:update 99999999-9999-9999-9999-999999999999 -i dyno -l notify -s 09928c40bf1b191b645174a19f7053d16a180da37332e719ef0998f4c0a2 -u https://example.com/hooks' -] - -Update.flags = { - app: flags.app(), - remote: flags.remote(), - pipeline: flags.string({ char: 'p', description: 'pipeline on which to list', hidden: true }), - include: flags.string({ char: 'i', description: 'comma delimited event types your server will receive ', required: true }), - level: flags.string({ char: 'l', description: 'notify does not retry, sync will retry until successful or timeout', required: true }), - secret: flags.string({ char: 's', description: 'value to sign delivery with in Heroku-Webhook-Hmac-SHA256 header' }), - authorization: flags.string({ char: 't', description: 'authoriation header to send with webhooks' }), - url: flags.string({ char: 'u', description: 'URL for receiver', required: true }) -} - -Update.args = [ - { name: 'id' } -] - -module.exports = Update - -// -// 'use strict' -// -// let co = require('co') -// let cli = require('heroku-cli-util') -// let webhookType = require('../../lib/webhook-type.js') -// -// function * run(context, heroku) { -// let {path, display} = webhookType(context) -// yield cli.action(`Updating webhook ${context.args.id} for ${display}`, {}, -// heroku.patch(`${path}/webhooks/${context.args.id}`, { -// headers: {Accept: 'application/vnd.heroku+json; version=3.webhooks'}, -// body: { -// include: context.flags.include && context.flags.include.split(',').map(s => s.trim()), -// level: context.flags.level, -// secret: context.flags.secret, -// url: context.flags.url, -// }, -// } -// )) -// } -// -// module.exports = { -// topic: 'webhooks', -// command: 'update', -// args: [ -// {name: 'id', description: 'id of webhook to remove'}, -// ], -// flags: [ -// {name: 'include', char: 'i', description: 'comma delimited webhook types', hasValue: true}, -// {name: 'level', char: 'l', description: 'webhook notification level', hasValue: true}, -// {name: 'secret', char: 's', description: 'comma delimited hook types', hasValue: true}, -// {name: 'url', char: 'u', description: 'url to send webhook to', hasValue: true}, -// {name: 'pipeline', char: 'p', hasValue: true, description: 'pipeline on which to remove', hidden: true}, -// ], -// description: 'updates a webhook in an app', -// help: `Example: -// -// $ heroku webhooks:update 99999999-9999-9999-9999-999999999999 -i dyno -l notify -s 09928c40bf1b191b645174a19f7053d16a180da37332e719ef0998f4c0a2 -u https://example.com/hooks -// `, -// wantsApp: true, -// needsAuth: true, -// run: cli.command(co.wrap(run)), -// } diff --git a/packages/webhooks-v5/lib/webhook-type.js b/packages/webhooks-v5/lib/webhook-type.js deleted file mode 100644 index b0b8b12ba6..0000000000 --- a/packages/webhooks-v5/lib/webhook-type.js +++ /dev/null @@ -1,17 +0,0 @@ -let cli = require('heroku-cli-util') - -module.exports = function (context) { - if (context.pipeline) { - return { - path: `/pipelines/${context.pipeline}`, - display: context.pipeline - } - } - if (context.app) { - return { - path: `/apps/${context.app}`, - display: cli.color.app(context.app) - } - } - throw new Error('No app specified') -} diff --git a/packages/webhooks-v5/package.json b/packages/webhooks-v5/package.json deleted file mode 100644 index aa66164566..0000000000 --- a/packages/webhooks-v5/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "@heroku-cli/plugin-webhooks-v5", - "description": "Heroku CLI plugin to manage webhooks.", - "version": "7.24.0", - "author": "Ransom Briggs (@ransombriggs)", - "bugs": "https://github.com/heroku/cli/issues", - "dependencies": { - "@heroku-cli/command": "^8.2.10", - "heroku-cli-util": "^8.0.11" - }, - "devDependencies": { - "@oclif/dev-cli": "^1.21.3", - "@oclif/plugin-legacy": "^1.1.4", - "chai": "^4.2.0", - "cross-env": "^5.2.0", - "mocha": "^5.2.0", - "mocha-junit-reporter": "1.18.0", - "nock": "10.0.6", - "nyc": "13.2.0" - }, - "engines": { - "node": ">=8.0.0" - }, - "files": [ - "oclif.manifest.json", - "index.js", - "commands", - "lib" - ], - "homepage": "https://github.com/heroku/cli/tree/master/packages/webhooks-v5", - "keywords": [ - "heroku-plugin" - ], - "license": "ISC", - "oclif": { - "commands": "./commands", - "topics": { - "webhooks": { - "description": "setup HTTP notifications of app activity" - } - }, - "repositoryPrefix": "<%- repo %>/blob/v<%- version %>/packages/webhooks-v5/<%- commandPath %>" - }, - "repository": "heroku/cli", - "scripts": { - "postpublish": "rm oclif.manifest.json", - "prepack": "oclif-dev manifest", - "test": "cross-env TZ=utc nyc mocha", - "version": "oclif-dev readme && git add README.md" - } -} diff --git a/packages/webhooks-v5/test/commands/webhooks/add.js b/packages/webhooks-v5/test/commands/webhooks/add.js deleted file mode 100644 index 71ef968ecc..0000000000 --- a/packages/webhooks-v5/test/commands/webhooks/add.js +++ /dev/null @@ -1,80 +0,0 @@ -'use strict' -/* globals describe it beforeEach cli */ - -let expect = require('chai').expect -let nock = require('nock') -let certs = require('../../../commands/webhooks/add') - -describe('heroku webhooks:add', function () { - beforeEach(function () { - cli.mockConsole() - nock.cleanAll() - }) - - it('# adds an webhook', function () { - let mock = nock('https://api.heroku.com') - .post('/apps/example/webhooks', { - include: ['foo', 'bar'], - level: 'notify', - secret: '1234', - url: 'http://foobar.com' - }) - .reply(200, {}) - - return certs.run([ - '--app', 'example', - '--include', 'foo,bar', - '--secret', '1234', - '--level', 'notify', - '--url', 'http://foobar.com' - ]).then(function () { - mock.done() - expect(cli.stderr).to.equal('Adding webhook to example... done\n') - expect(cli.stdout).to.equal('') - }) - }) - - it('# adds an webhook with secret', function () { - let mock = nock('https://api.heroku.com') - .post('/apps/example/webhooks', { - include: ['foo', 'bar'], - level: 'notify', - url: 'http://foobar.com' - }) - .reply(200, {}, { 'Heroku-Webhook-Secret': '1234' }) - - return certs.run([ - '--app', 'example', - '--include', 'foo,bar', - '--level', 'notify', - '--url', 'http://foobar.com' - ]).then(function () { - mock.done() - expect(cli.stderr).to.equal('Adding webhook to example... done\n') - expect(cli.stdout).to.equal('=== Webhooks Signing Secret\n1234\n') - }) - }) - - it('# adds a pipeline webhook', function () { - let mock = nock('https://api.heroku.com') - .post('/pipelines/example/webhooks', { - include: ['foo', 'bar'], - level: 'notify', - secret: '1234', - url: 'http://foobar.com' - }) - .reply(200, {}) - - return certs.run([ - '--pipeline', 'example', - '--include', 'foo,bar', - '--secret', '1234', - '--level', 'notify', - '--url', 'http://foobar.com' - ]).then(function () { - mock.done() - expect(cli.stderr).to.equal('Adding webhook to example... done\n') - expect(cli.stdout).to.equal('') - }) - }) -}) diff --git a/packages/webhooks-v5/test/commands/webhooks/deliveries/index.js b/packages/webhooks-v5/test/commands/webhooks/deliveries/index.js deleted file mode 100644 index dccf495be8..0000000000 --- a/packages/webhooks-v5/test/commands/webhooks/deliveries/index.js +++ /dev/null @@ -1,177 +0,0 @@ -/* eslint-disable camelcase */ -'use strict' -/* globals describe it beforeEach cli */ - -let expect = require('chai').expect -let nock = require('nock') -let certs = require('../../../../commands/webhooks/deliveries') -const unwrap = require('../../../unwrap') - -describe('heroku webhooks:deliveries', function () { - beforeEach(function () { - cli.mockConsole() - nock.cleanAll() - }) - - it('# lists deliveries', function () { - let mock = nock('https://api.heroku.com', { - reqheaders: { range: 'seq ..; order=desc,max=1000' } - }) - .get('/apps/example/webhook-deliveries') - .reply(206, [{ - id: '66666666-6666-6666-6666-666666666666', - event: { - id: '55555555-5555-5555-5555-555555555555', - include: 'api:build' - }, - webhook: { - id: '44444444-4444-4444-4444-444444444444', - level: 'notify' - }, - status: 'pending', - num_attempts: 4, - created_at: '2017-08-17T20:22:38Z' - }, { - id: '99999999-9999-9999-9999-999999999999', - event: { - id: '88888888-8888-8888-8888-888888888888', - include: 'api:build' - }, - webhook: { - id: '77777777-7777-7777-7777-777777777777', - level: 'notify' - }, - last_attempt: { - code: 401, - error_class: 'Foobar' - }, - status: 'retrying', - num_attempts: 4, - created_at: '2017-08-17T20:22:37Z', - next_attempt_at: '2017-08-17T20:22:39Z' - }], { 'next-range': 'id 99999999-9999-9999-9999-999999999999' }) - - return certs.run(['--app', 'example']).then(function () { - mock.done() - expect(cli.stderr).to.equal('') - expect(cli.stdout).to.equal( - `Delivery ID Created Status Include Level Attempts Code Error Next Attempt -──────────────────────────────────── ──────────────────── ──────── ───────── ────── ──────── ──── ────── ──────────────────── -99999999-9999-9999-9999-999999999999 2017-08-17T20:22:37Z retrying api:build notify 4 401 Foobar 2017-08-17T20:22:39Z -66666666-6666-6666-6666-666666666666 2017-08-17T20:22:38Z pending api:build notify 4 -`) - }) - }) - - it('# lists deliveries by state', function () { - let mock = nock('https://api.heroku.com', { - reqheaders: { range: 'seq ..; order=desc,max=1000' } - }) - .get('/apps/example/webhook-deliveries?eq[status]=pending') - .reply(206, [{ - id: '66666666-6666-6666-6666-666666666666', - event: { - id: '55555555-5555-5555-5555-555555555555', - include: 'api:build' - }, - webhook: { - id: '44444444-4444-4444-4444-444444444444', - level: 'notify' - }, - status: 'pending', - num_attempts: 4, - created_at: '2017-08-17T20:22:38Z' - }]) - - return certs.run(['--app', 'example', '--status', 'pending']).then(function () { - mock.done() - expect(cli.stderr).to.equal('') - expect(cli.stdout).to.equal( - `Delivery ID Created Status Include Level Attempts Code Error Next Attempt -──────────────────────────────────── ──────────────────── ─────── ───────── ────── ──────── ──── ───── ──────────── -66666666-6666-6666-6666-666666666666 2017-08-17T20:22:38Z pending api:build notify 4 -`) - }) - }) - - it('# lists 1000 deliveries', function () { - let delivery = { - id: '66666666-6666-6666-6666-666666666666', - event: { - id: '55555555-5555-5555-5555-555555555555', - include: 'api:build' - }, - webhook: { - id: '44444444-4444-4444-4444-444444444444', - level: 'notify' - }, - status: 'pending', - num_attempts: 4, - created_at: '2017-08-17T20:22:38Z' - } - - let mock = nock('https://api.heroku.com', { - reqheaders: { range: 'seq ..; order=desc,max=1000' } - }) - .get('/apps/example/webhook-deliveries') - .reply(206, new Array(1000).fill().map(() => delivery)) - - return certs.run(['--app', 'example']).then(function () { - mock.done() - expect(unwrap(cli.stderr)).to.equal('Only showing the 1000 most recent deliveries It is possible to filter deliveries by using the --status flag\n') - }) - }) - - it('# lists empty deliveries', function () { - let mock = nock('https://api.heroku.com') - .get('/apps/example/webhook-deliveries') - .reply(200, []) - - return certs.run(['--app', 'example']).then(function () { - mock.done() - expect(cli.stderr).to.equal('') - expect(cli.stdout).to.equal('example has no deliveries\n') - }) - }) - - it('# lists deliveries (piplines)', function () { - let mock = nock('https://api.heroku.com') - .get('/pipelines/example/webhook-deliveries') - .reply(200, [{ - id: '66666666-6666-6666-6666-666666666666', - event: { - id: '55555555-5555-5555-5555-555555555555', - include: 'api:build' - }, - webhook: { - id: '44444444-4444-4444-4444-444444444444', - level: 'notify' - }, - status: 'pending', - num_attempts: 4, - created_at: '2017-08-17T20:22:38Z' - }]) - - return certs.run(['--pipeline', 'example']).then(function () { - mock.done() - expect(cli.stderr).to.equal('') - expect(cli.stdout).to.equal( - `Delivery ID Created Status Include Level Attempts Code Error Next Attempt -──────────────────────────────────── ──────────────────── ─────── ───────── ────── ──────── ──── ───── ──────────── -66666666-6666-6666-6666-666666666666 2017-08-17T20:22:38Z pending api:build notify 4 -`) - }) - }) - - it('# lists empty deliveries (pipelines)', function () { - let mock = nock('https://api.heroku.com') - .get('/pipelines/example/webhook-deliveries') - .reply(200, []) - - return certs.run(['--pipeline', 'example']).then(function () { - mock.done() - expect(cli.stderr).to.equal('') - expect(cli.stdout).to.equal('example has no deliveries\n') - }) - }) -}) diff --git a/packages/webhooks-v5/test/commands/webhooks/events/index.js b/packages/webhooks-v5/test/commands/webhooks/events/index.js deleted file mode 100644 index ca3082164e..0000000000 --- a/packages/webhooks-v5/test/commands/webhooks/events/index.js +++ /dev/null @@ -1,87 +0,0 @@ -/* eslint-disable camelcase */ -'use strict' -/* globals describe it beforeEach cli */ - -let expect = require('chai').expect -let nock = require('nock') -let certs = require('../../../../commands/webhooks/events') -const unwrap = require('../../../unwrap') - -describe('heroku webhooks:events', function () { - beforeEach(function () { - cli.mockConsole() - nock.cleanAll() - }) - - it('# lists events', function () { - let mock = nock('https://api.heroku.com') - .get('/apps/example/webhook-events') - .reply(200, [{ - id: '99999999-9999-9999-9999-999999999999', - payload: { - published_at: '2016-08-31T21:55:06Z', - resource: 'api:release', - action: 'create' - } - - }]) - - return certs.run(['--app', 'example']).then(function () { - mock.done() - expect(unwrap(cli.stderr)).to.equal('heroku webhooks:event is deprecated, please use heroku webhooks:deliveries\n') - expect(cli.stdout).to.equal( - `Event ID Resource Action Published At -──────────────────────────────────── ─────────── ────── ──────────────────── -99999999-9999-9999-9999-999999999999 api:release create 2016-08-31T21:55:06Z -`) - }) - }) - - it('# lists events (pipelines)', function () { - let mock = nock('https://api.heroku.com') - .get('/pipelines/example/webhook-events') - .reply(200, [{ - id: '99999999-9999-9999-9999-999999999999', - payload: { - published_at: '2016-08-31T21:55:06Z', - resource: 'api:release', - action: 'create' - } - - }]) - - return certs.run(['--pipeline', 'example']).then(function () { - mock.done() - expect(unwrap(cli.stderr)).to.equal('heroku webhooks:event is deprecated, please use heroku webhooks:deliveries\n') - expect(cli.stdout).to.equal( - `Event ID Resource Action Published At -──────────────────────────────────── ─────────── ────── ──────────────────── -99999999-9999-9999-9999-999999999999 api:release create 2016-08-31T21:55:06Z -`) - }) - }) - - it('# lists empty events', function () { - let mock = nock('https://api.heroku.com') - .get('/apps/example/webhook-events') - .reply(200, []) - - return certs.run(['--app', 'example']).then(function () { - mock.done() - expect(unwrap(cli.stderr)).to.equal('heroku webhooks:event is deprecated, please use heroku webhooks:deliveries\n') - expect(cli.stdout).to.equal('example has no events\n') - }) - }) - - it('# lists empty events (pipelines)', function () { - let mock = nock('https://api.heroku.com') - .get('/pipelines/example/webhook-events') - .reply(200, []) - - return certs.run(['--pipeline', 'example']).then(function () { - mock.done() - expect(unwrap(cli.stderr)).to.equal('heroku webhooks:event is deprecated, please use heroku webhooks:deliveries\n') - expect(cli.stdout).to.equal('example has no events\n') - }) - }) -}) diff --git a/packages/webhooks-v5/test/commands/webhooks/events/info.js b/packages/webhooks-v5/test/commands/webhooks/events/info.js deleted file mode 100644 index f7217c14ba..0000000000 --- a/packages/webhooks-v5/test/commands/webhooks/events/info.js +++ /dev/null @@ -1,79 +0,0 @@ -/* eslint-disable camelcase */ -'use strict' -/* globals describe it beforeEach cli */ - -let expect = require('chai').expect -let nock = require('nock') -let certs = require('../../../../commands/webhooks/events/info') -const unwrap = require('../../../unwrap') - -describe('heroku webhooks:events:info', function () { - beforeEach(function () { - cli.mockConsole() - nock.cleanAll() - }) - - it('# shows an event', function () { - let mock = nock('https://api.heroku.com') - .get('/apps/example/webhook-events/99999999-9999-9999-9999-999999999999') - .reply(200, { - id: '99999999-9999-9999-9999-999999999999', - payload: { - published_at: '2016-08-31T21:55:06Z', - resource: 'api:release', - action: 'create', - data: { - foo: 'bar' - } - } - }) - - return certs.run(['--app', 'example', '99999999-9999-9999-9999-999999999999']).then(function () { - mock.done() - expect(unwrap(cli.stderr)).to.equal('heroku webhooks:event:info is deprecated, please use heroku webhooks:deliveries:info\n') - expect(cli.stdout).to.equal( - `=== 99999999-9999-9999-9999-999999999999 -payload: { - "published_at": "2016-08-31T21:55:06Z", - "resource": "api:release", - "action": "create", - "data": { - "foo": "bar" - } -} -`) - }) - }) - - it('# shows an event (pipelines)', function () { - let mock = nock('https://api.heroku.com') - .get('/pipelines/example/webhook-events/99999999-9999-9999-9999-999999999999') - .reply(200, { - id: '99999999-9999-9999-9999-999999999999', - payload: { - published_at: '2016-08-31T21:55:06Z', - resource: 'api:release', - action: 'create', - data: { - foo: 'bar' - } - } - }) - - return certs.run(['--pipeline', 'example', '99999999-9999-9999-9999-999999999999']).then(function () { - mock.done() - expect(unwrap(cli.stderr)).to.equal('heroku webhooks:event:info is deprecated, please use heroku webhooks:deliveries:info\n') - expect(cli.stdout).to.equal( - `=== 99999999-9999-9999-9999-999999999999 -payload: { - "published_at": "2016-08-31T21:55:06Z", - "resource": "api:release", - "action": "create", - "data": { - "foo": "bar" - } -} -`) - }) - }) -}) diff --git a/packages/webhooks-v5/test/commands/webhooks/index.js b/packages/webhooks-v5/test/commands/webhooks/index.js deleted file mode 100644 index 952451ab9d..0000000000 --- a/packages/webhooks-v5/test/commands/webhooks/index.js +++ /dev/null @@ -1,79 +0,0 @@ -'use strict' -/* globals describe it beforeEach cli */ - -let expect = require('chai').expect -let nock = require('nock') -let certs = require('../../../commands/webhooks') - -describe('heroku webhooks:add', function () { - beforeEach(function () { - cli.mockConsole() - nock.cleanAll() - }) - - it('# lists webhooks', function () { - let mock = nock('https://api.heroku.com') - .get('/apps/example/webhooks') - .reply(200, [{ - id: '99999999-9999-9999-9999-999999999999', - include: ['foo', 'bar'], - level: 'notify', - url: 'http://foobar.com' - }]) - - return certs.run(['--app', 'example']).then(function () { - mock.done() - expect(cli.stderr).to.equal('') - expect(cli.stdout).to.equal( - `Webhook ID URL Include Level -──────────────────────────────────── ───────────────── ─────── ────── -99999999-9999-9999-9999-999999999999 http://foobar.com foo,bar notify -`) - }) - }) - - it('# lists empty webhooks', function () { - let mock = nock('https://api.heroku.com') - .get('/apps/example/webhooks') - .reply(200, []) - - return certs.run(['--app', 'example']).then(function () { - mock.done() - expect(cli.stderr).to.equal('') - expect(cli.stdout).to.equal('example has no webhooks\nUse heroku webhooks:add to add one.\n') - }) - }) - - it('# lists pipeline webhooks', function () { - let mock = nock('https://api.heroku.com') - .get('/pipelines/example/webhooks') - .reply(200, [{ - id: '99999999-9999-9999-9999-999999999999', - include: ['foo', 'bar'], - level: 'notify', - url: 'http://foobar.com' - }]) - - return certs.run(['--pipeline', 'example']).then(function () { - mock.done() - expect(cli.stderr).to.equal('') - expect(cli.stdout).to.equal( - `Webhook ID URL Include Level -──────────────────────────────────── ───────────────── ─────── ────── -99999999-9999-9999-9999-999999999999 http://foobar.com foo,bar notify -`) - }) - }) - - it('# lists empty pipeline webhooks', function () { - let mock = nock('https://api.heroku.com') - .get('/pipelines/example/webhooks') - .reply(200, []) - - return certs.run(['--pipeline', 'example']).then(function () { - mock.done() - expect(cli.stderr).to.equal('') - expect(cli.stdout).to.equal('example has no webhooks\nUse heroku webhooks:add to add one.\n') - }) - }) -}) diff --git a/packages/webhooks-v5/test/commands/webhooks/info.js b/packages/webhooks-v5/test/commands/webhooks/info.js deleted file mode 100644 index b871eede06..0000000000 --- a/packages/webhooks-v5/test/commands/webhooks/info.js +++ /dev/null @@ -1,59 +0,0 @@ -'use strict' -/* globals describe it beforeEach cli */ - -let expect = require('chai').expect -let nock = require('nock') -let info = require('../../../commands/webhooks/info') - -describe('heroku webhooks:deliveries:info', function () { - beforeEach(function () { - cli.mockConsole() - nock.cleanAll() - }) - - it('# shows a webhook', function () { - let mock = nock('https://api.heroku.com') - .get('/apps/example/webhooks/99999999-9999-9999-9999-999999999999') - .reply(200, { - id: '99999999-9999-9999-9999-999999999999', - include: ['foo', 'bar'], - level: 'notify', - url: 'http://foobar.com' - }) - - return info.run(['99999999-9999-9999-9999-999999999999', '--app', 'example']).then(function () { - mock.done() - expect(cli.stderr).to.equal('') - expect(cli.stdout).to.equal( - `=== 99999999-9999-9999-9999-999999999999 -Include: foo,bar -Level: notify -URL: http://foobar.com -Webhook ID: 99999999-9999-9999-9999-999999999999 -`) - }) - }) - - it('# shows a webhook (pipelines)', function () { - let mock = nock('https://api.heroku.com') - .get('/pipelines/example/webhooks/99999999-9999-9999-9999-999999999999') - .reply(200, { - id: '99999999-9999-9999-9999-999999999999', - include: ['foo', 'bar'], - level: 'notify', - url: 'http://foobar.com' - }) - - return info.run(['99999999-9999-9999-9999-999999999999', '--pipeline', 'example']).then(function () { - mock.done() - expect(cli.stderr).to.equal('') - expect(cli.stdout).to.equal( - `=== 99999999-9999-9999-9999-999999999999 -Include: foo,bar -Level: notify -URL: http://foobar.com -Webhook ID: 99999999-9999-9999-9999-999999999999 -`) - }) - }) -}) diff --git a/packages/webhooks-v5/test/commands/webhooks/remove.js b/packages/webhooks-v5/test/commands/webhooks/remove.js deleted file mode 100644 index 93cb6a1c51..0000000000 --- a/packages/webhooks-v5/test/commands/webhooks/remove.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict' -/* globals describe it beforeEach cli */ - -let expect = require('chai').expect -let nock = require('nock') -let certs = require('../../../commands/webhooks/remove') - -describe('heroku webhooks:add', function () { - beforeEach(function () { - cli.mockConsole() - nock.cleanAll() - }) - - it('# removes webhooks', function () { - let mock = nock('https://api.heroku.com') - .delete('/apps/example/webhooks/99999999-9999-9999-9999-999999999999') - .reply(200, {}) - - return certs.run(['99999999-9999-9999-9999-999999999999', '--app', 'example']).then(function () { - mock.done() - expect(cli.stdout).to.equal('') - expect(cli.stderr).to.equal('Removing webhook 99999999-9999-9999-9999-999999999999 from example... done\n') - }) - }) - - it('# removes webhooks (pipelines)', function () { - let mock = nock('https://api.heroku.com') - .delete('/pipelines/example/webhooks/99999999-9999-9999-9999-999999999999') - .reply(200, {}) - - return certs.run(['99999999-9999-9999-9999-999999999999', '--pipeline', 'example']).then(function () { - mock.done() - expect(cli.stdout).to.equal('') - expect(cli.stderr).to.equal('Removing webhook 99999999-9999-9999-9999-999999999999 from example... done\n') - }) - }) -}) diff --git a/packages/webhooks-v5/test/commands/webhooks/update.js b/packages/webhooks-v5/test/commands/webhooks/update.js deleted file mode 100644 index 4fb0a62624..0000000000 --- a/packages/webhooks-v5/test/commands/webhooks/update.js +++ /dev/null @@ -1,61 +0,0 @@ -'use strict' -/* globals describe it beforeEach cli */ - -let expect = require('chai').expect -let nock = require('nock') -let certs = require('../../../commands/webhooks/update') - -describe('heroku webhooks:update', function () { - beforeEach(function () { - cli.mockConsole() - nock.cleanAll() - }) - - it('# updates a webhook', function () { - let mock = nock('https://api.heroku.com') - .patch('/apps/example/webhooks/99999999-9999-9999-9999-999999999999', { - include: ['foo', 'bar'], - level: 'notify', - secret: '1234', - url: 'http://foobar.com' - }) - .reply(200, {}) - - return certs.run([ - '99999999-9999-9999-9999-999999999999', - '--app', 'example', - '--include', 'foo,bar', - '--secret', '1234', - '--level', 'notify', - '--url', 'http://foobar.com' - ]).then(function () { - mock.done() - expect(cli.stderr).to.equal('Updating webhook 99999999-9999-9999-9999-999999999999 for example... done\n') - expect(cli.stdout).to.equal('') - }) - }) - - it('# updates a webhook', function () { - let mock = nock('https://api.heroku.com') - .patch('/pipelines/example/webhooks/99999999-9999-9999-9999-999999999999', { - include: ['foo', 'bar'], - level: 'notify', - secret: '1234', - url: 'http://foobar.com' - }) - .reply(200, {}) - - return certs.run([ - '99999999-9999-9999-9999-999999999999', - '--pipeline', 'example', - '--include', 'foo,bar', - '--secret', '1234', - '--level', 'notify', - '--url', 'http://foobar.com' - ]).then(function () { - mock.done() - expect(cli.stderr).to.equal('Updating webhook 99999999-9999-9999-9999-999999999999 for example... done\n') - expect(cli.stdout).to.equal('') - }) - }) -}) diff --git a/packages/webhooks-v5/test/helpers.js b/packages/webhooks-v5/test/helpers.js deleted file mode 100644 index 3933dd488f..0000000000 --- a/packages/webhooks-v5/test/helpers.js +++ /dev/null @@ -1,9 +0,0 @@ -'use strict' -/* globals cli */ - -global.cli = require('heroku-cli-util') -cli.raiseErrors = true -cli.color.enabled = false - -let nock = require('nock') -nock.disableNetConnect() diff --git a/packages/webhooks-v5/test/mocha.opts b/packages/webhooks-v5/test/mocha.opts deleted file mode 100644 index 2e333ba791..0000000000 --- a/packages/webhooks-v5/test/mocha.opts +++ /dev/null @@ -1,4 +0,0 @@ ---require ./test/helpers.js ---reporter list ---recursive ---timeout 50000 diff --git a/packages/webhooks-v5/test/unwrap.js b/packages/webhooks-v5/test/unwrap.js deleted file mode 100644 index e8ca37ef19..0000000000 --- a/packages/webhooks-v5/test/unwrap.js +++ /dev/null @@ -1,10 +0,0 @@ -'use strict' - -function unwrap (str) { - let sanitize = str.replace(/\n ([▸!]) {3}/g, '') - sanitize = sanitize.replace(/ ([▸!]) {4}/g, '') - - return sanitize -} - -module.exports = unwrap diff --git a/packages/webhooks/.circleci/config.yml b/packages/webhooks/.circleci/config.yml new file mode 100644 index 0000000000..dd07079240 --- /dev/null +++ b/packages/webhooks/.circleci/config.yml @@ -0,0 +1,60 @@ +--- +version: 2 +jobs: + node-latest: &test + docker: + - image: node:latest + working_directory: ~/cli + steps: + - checkout + - restore_cache: &restore_cache + keys: + - v1-npm-{{checksum ".circleci/config.yml"}}-{{checksum "yarn.lock"}} + - v1-npm-{{checksum ".circleci/config.yml"}} + - run: + name: Install dependencies + command: yarn + - run: ./bin/run --help + - run: + name: Testing + command: yarn test + - run: + name: Submitting code coverage to codecov + command: | + ./node_modules/.bin/nyc report --reporter text-lcov > coverage.lcov + curl -s https://codecov.io/bash | bash + node-8: + <<: *test + docker: + - image: node:8 + node-10: + <<: *test + docker: + - image: node:10 + cache: + <<: *test + steps: + - checkout + - run: + name: Install dependencies + command: yarn + - save_cache: + key: v1-npm-{{checksum ".circleci/config.yml"}}-{{checksum "yarn.lock"}} + paths: + - ~/cli/node_modules + - /usr/local/share/.cache/yarn + - /usr/local/share/.config/yarn + +workflows: + version: 2 + "webhooks": + jobs: + - node-latest + - node-8 + - node-10 + - cache: + filters: + tags: + only: /^v.*/ + branches: + ignore: /.*/ diff --git a/packages/webhooks/.editorconfig b/packages/webhooks/.editorconfig new file mode 100644 index 0000000000..beffa3084e --- /dev/null +++ b/packages/webhooks/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/packages/webhooks/.gitignore b/packages/webhooks/.gitignore new file mode 100644 index 0000000000..9d6ea2ca58 --- /dev/null +++ b/packages/webhooks/.gitignore @@ -0,0 +1,8 @@ +*-debug.log +*-error.log +/.nyc_output +/dist +/lib +/package-lock.json +/tmp +node_modules diff --git a/packages/webhooks/CHANGELOG.md b/packages/webhooks/CHANGELOG.md new file mode 100644 index 0000000000..1eac94bcd7 --- /dev/null +++ b/packages/webhooks/CHANGELOG.md @@ -0,0 +1,11 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [7.29.0](https://github.com/heroku/cli/compare/v7.28.0...v7.29.0) (2019-08-21) + + +### Features + +* **webhooks:** add oclif version of webhooks plugin ([#1253](https://github.com/heroku/cli/issues/1253)) ([110c516](https://github.com/heroku/cli/commit/110c516)) diff --git a/packages/webhooks/README.md b/packages/webhooks/README.md new file mode 100644 index 0000000000..6588f3d0ef --- /dev/null +++ b/packages/webhooks/README.md @@ -0,0 +1,230 @@ +webhooks +======== + + + +[![oclif](https://img.shields.io/badge/cli-oclif-brightgreen.svg)](https://oclif.io) +[![Version](https://img.shields.io/npm/v/webhooks.svg)](https://npmjs.org/package/webhooks) +[![CircleCI](https://circleci.com/gh/chadian/webhooks/tree/master.svg?style=shield)](https://circleci.com/gh/chadian/webhooks/tree/master) +[![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/chadian/webhooks?branch=master&svg=true)](https://ci.appveyor.com/project/chadian/webhooks/branch/master) +[![Codecov](https://codecov.io/gh/chadian/webhooks/branch/master/graph/badge.svg)](https://codecov.io/gh/chadian/webhooks) +[![Downloads/week](https://img.shields.io/npm/dw/webhooks.svg)](https://npmjs.org/package/webhooks) +[![License](https://img.shields.io/npm/l/webhooks.svg)](https://github.com/chadian/webhooks/blob/master/package.json) + + +* [Usage](#usage) +* [Commands](#commands) + +# Usage + +```sh-session +$ npm install -g @heroku-cli/plugin-webhooks +$ heroku COMMAND +running command... +$ heroku (-v|--version|version) +@heroku-cli/plugin-webhooks/7.29.0 darwin-x64 node-v10.2.1 +$ heroku --help [COMMAND] +USAGE + $ heroku COMMAND +... +``` + +# Commands + +* [`heroku base`](#heroku-base) +* [`heroku webhooks`](#heroku-webhooks) +* [`heroku webhooks:add`](#heroku-webhooksadd) +* [`heroku webhooks:deliveries`](#heroku-webhooksdeliveries) +* [`heroku webhooks:deliveries:info ID`](#heroku-webhooksdeliveriesinfo-id) +* [`heroku webhooks:events`](#heroku-webhooksevents) +* [`heroku webhooks:events:info ID`](#heroku-webhookseventsinfo-id) +* [`heroku webhooks:info ID`](#heroku-webhooksinfo-id) +* [`heroku webhooks:remove ID`](#heroku-webhooksremove-id) +* [`heroku webhooks:update ID`](#heroku-webhooksupdate-id) + +## `heroku base` + +``` +USAGE + $ heroku base +``` + +_See code: [src/commands/base.ts](https://github.com/heroku/cli/blob/v7.29.0/src/commands/base.ts)_ + +## `heroku webhooks` + +list webhooks on an app + +``` +USAGE + $ heroku webhooks + +OPTIONS + -a, --app=app app to run command against + -r, --remote=remote git remote of app to use + +EXAMPLE + $ heroku webhooks +``` + +_See code: [src/commands/webhooks/index.ts](https://github.com/heroku/cli/blob/v7.29.0/src/commands/webhooks/index.ts)_ + +## `heroku webhooks:add` + +add a webhook to an app + +``` +USAGE + $ heroku webhooks:add + +OPTIONS + -a, --app=app app to run command against + -i, --include=include (required) comma delimited event types your server will receive + -l, --level=level (required) notify does not retry, sync will retry until successful or timeout + -r, --remote=remote git remote of app to use + -s, --secret=secret value to sign delivery with in Heroku-Webhook-Hmac-SHA256 header + -t, --authorization=authorization authoriation header to send with webhooks + -u, --url=url (required) URL for receiver + +EXAMPLE + $ heroku webhooks:add -i api:dyno -l notify -u https://example.com/hooks +``` + +_See code: [src/commands/webhooks/add.ts](https://github.com/heroku/cli/blob/v7.29.0/src/commands/webhooks/add.ts)_ + +## `heroku webhooks:deliveries` + +list webhook deliveries on an app + +``` +USAGE + $ heroku webhooks:deliveries + +OPTIONS + -a, --app=app app to run command against + -r, --remote=remote git remote of app to use + -s, --status=status filter deliveries by status + +EXAMPLE + $ heroku webhooks:deliveries +``` + +_See code: [src/commands/webhooks/deliveries/index.ts](https://github.com/heroku/cli/blob/v7.29.0/src/commands/webhooks/deliveries/index.ts)_ + +## `heroku webhooks:deliveries:info ID` + +info for a webhook event on an app + +``` +USAGE + $ heroku webhooks:deliveries:info ID + +OPTIONS + -a, --app=app app to run command against + -r, --remote=remote git remote of app to use + +EXAMPLE + $ heroku webhooks:deliveries:info 99999999-9999-9999-9999-999999999999 +``` + +_See code: [src/commands/webhooks/deliveries/info.ts](https://github.com/heroku/cli/blob/v7.29.0/src/commands/webhooks/deliveries/info.ts)_ + +## `heroku webhooks:events` + +list webhook events on an app + +``` +USAGE + $ heroku webhooks:events + +OPTIONS + -a, --app=app app to run command against + -r, --remote=remote git remote of app to use + +EXAMPLE + $ heroku webhooks:events +``` + +_See code: [src/commands/webhooks/events/index.ts](https://github.com/heroku/cli/blob/v7.29.0/src/commands/webhooks/events/index.ts)_ + +## `heroku webhooks:events:info ID` + +info for a webhook event on an app + +``` +USAGE + $ heroku webhooks:events:info ID + +OPTIONS + -a, --app=app app to run command against + -r, --remote=remote git remote of app to use + +EXAMPLE + $ heroku webhooks:events:info 99999999-9999-9999-9999-999999999999 +``` + +_See code: [src/commands/webhooks/events/info.ts](https://github.com/heroku/cli/blob/v7.29.0/src/commands/webhooks/events/info.ts)_ + +## `heroku webhooks:info ID` + +info for a webhook on an app + +``` +USAGE + $ heroku webhooks:info ID + +OPTIONS + -a, --app=app app to run command against + -r, --remote=remote git remote of app to use + +EXAMPLE + $ heroku webhooks:info 99999999-9999-9999-9999-999999999999 +``` + +_See code: [src/commands/webhooks/info.ts](https://github.com/heroku/cli/blob/v7.29.0/src/commands/webhooks/info.ts)_ + +## `heroku webhooks:remove ID` + +removes a webhook from an app + +``` +USAGE + $ heroku webhooks:remove ID + +ARGUMENTS + ID id of webhook to remove + +OPTIONS + -a, --app=app app to run command against + -r, --remote=remote git remote of app to use + +EXAMPLE + $ heroku webhooks:remove 99999999-9999-9999-9999-999999999999 +``` + +_See code: [src/commands/webhooks/remove.ts](https://github.com/heroku/cli/blob/v7.29.0/src/commands/webhooks/remove.ts)_ + +## `heroku webhooks:update ID` + +updates a webhook in an app + +``` +USAGE + $ heroku webhooks:update ID + +OPTIONS + -a, --app=app app to run command against + -i, --include=include (required) comma delimited event types your server will receive + -l, --level=level (required) notify does not retry, sync will retry until successful or timeout + -r, --remote=remote git remote of app to use + -s, --secret=secret value to sign delivery with in Heroku-Webhook-Hmac-SHA256 header + -t, --authorization=authorization authoriation header to send with webhooks + -u, --url=url (required) URL for receiver + +EXAMPLE + $ heroku webhooks:update 99999999-9999-9999-9999-999999999999 -i dyno -l notify -s + 09928c40bf1b191b645174a19f7053d16a180da37332e719ef0998f4c0a2 -u https://example.com/hooks +``` + +_See code: [src/commands/webhooks/update.ts](https://github.com/heroku/cli/blob/v7.29.0/src/commands/webhooks/update.ts)_ + diff --git a/packages/webhooks/appveyor.yml b/packages/webhooks/appveyor.yml new file mode 100644 index 0000000000..b2537719ab --- /dev/null +++ b/packages/webhooks/appveyor.yml @@ -0,0 +1,23 @@ +environment: + nodejs_version: "10" +cache: + - '%LOCALAPPDATA%\Yarn -> appveyor.yml' + - node_modules -> yarn.lock + +install: + - ps: Install-Product node $env:nodejs_version x64 + - yarn +test_script: + - .\bin\run --help + - yarn test + +after_test: + - .\node_modules\.bin\nyc report --reporter text-lcov > coverage.lcov + - ps: | + $env:PATH = 'C:\msys64\usr\bin;' + $env:PATH + Invoke-WebRequest -Uri 'https://codecov.io/bash' -OutFile codecov.sh + bash codecov.sh + + +build: off + diff --git a/packages/webhooks/bin/run b/packages/webhooks/bin/run new file mode 100755 index 0000000000..3c4ae3ac07 --- /dev/null +++ b/packages/webhooks/bin/run @@ -0,0 +1,4 @@ +#!/usr/bin/env node + +require('@oclif/command').run() +.catch(require('@oclif/errors/handle')) diff --git a/packages/webhooks/bin/run.cmd b/packages/webhooks/bin/run.cmd new file mode 100644 index 0000000000..968fc30758 --- /dev/null +++ b/packages/webhooks/bin/run.cmd @@ -0,0 +1,3 @@ +@echo off + +node "%~dp0\run" %* diff --git a/packages/webhooks/package.json b/packages/webhooks/package.json new file mode 100644 index 0000000000..07b13bb733 --- /dev/null +++ b/packages/webhooks/package.json @@ -0,0 +1,60 @@ +{ + "name": "@heroku-cli/plugin-webhooks", + "description": "Heroku CLI plugin to manage webhooks", + "version": "7.29.0", + "author": "Chad Carbert @chadian", + "bugs": "https://github.com/heroku/cli/issues", + "dependencies": { + "@heroku-cli/color": "^1.1.14", + "@heroku-cli/command": "^8.2.11", + "@oclif/command": "^1", + "@oclif/config": "^1", + "cli-ux": "^5.2.1", + "tslib": "^1" + }, + "devDependencies": { + "@oclif/dev-cli": "^1", + "@oclif/plugin-help": "^2", + "@oclif/test": "^1", + "@oclif/tslint": "^3", + "@types/chai": "^4", + "@types/mocha": "^5", + "@types/node": "^10", + "chai": "^4", + "date-fns": "^1.30.1", + "globby": "^8", + "mocha": "^5", + "nyc": "^13", + "ts-node": "^8", + "tslint": "^5", + "typescript": "^3.3" + }, + "engines": { + "node": ">=8.0.0" + }, + "files": [ + "/lib", + "/oclif.manifest.json", + "/yarn.lock" + ], + "homepage": "https://github.com/heroku/cli/tree/master/packages/webhooks", + "keywords": [ + "heroku-plugin" + ], + "license": "MIT", + "oclif": { + "commands": "./lib/commands", + "bin": "heroku", + "devPlugins": [ + "@oclif/plugin-help" + ] + }, + "repository": "heroku/cli", + "scripts": { + "postpack": "rm -f oclif.manifest.json", + "posttest": "tslint -p test -t stylish", + "prepack": "rm -rf lib && tsc -b && oclif-dev manifest && oclif-dev readme", + "test": "nyc --extension .ts mocha --forbid-only \"test/**/*.test.ts\"", + "version": "oclif-dev readme && git add README.md" + } +} diff --git a/packages/webhooks/src/commands/base.ts b/packages/webhooks/src/commands/base.ts new file mode 100644 index 0000000000..f16316c3c9 --- /dev/null +++ b/packages/webhooks/src/commands/base.ts @@ -0,0 +1,36 @@ +import color from '@heroku-cli/color' +import {APIClient, Command} from '@heroku-cli/command' + +import {IConfig} from '@oclif/config' + +export default abstract class extends Command { + webhooksClient: APIClient + + protected constructor(argv: string[], config: IConfig) { + super(argv, config) + + const client = new APIClient(this.config, {}) + client.defaults.headers = { + ...this.heroku.defaults.headers, + Accept: 'application/vnd.heroku+json; version=3.webhooks', + authorization: `Basic ${Buffer.from(':' + this.heroku.auth).toString('base64')}` + } + this.webhooksClient = client + } + + webhookType(context: {pipeline?: string, app?: string}): {path: string, display: string} { + if (context.pipeline) { + return { + path: `/pipelines/${context.pipeline}`, + display: context.pipeline + } + } + if (context.app) { + return { + path: `/apps/${context.app}`, + display: color.app(context.app) + } + } + return this.error('No app specified') + } +} diff --git a/packages/webhooks/src/commands/webhooks/add.ts b/packages/webhooks/src/commands/webhooks/add.ts new file mode 100644 index 0000000000..a4c3e750c0 --- /dev/null +++ b/packages/webhooks/src/commands/webhooks/add.ts @@ -0,0 +1,51 @@ +import {flags} from '@heroku-cli/command' +import {cli} from 'cli-ux' + +import BaseCommand from '../base' + +export default class WebhooksAdd extends BaseCommand { + static description = 'add a webhook to an app' + + static examples = [ + '$ heroku webhooks:add -i api:dyno -l notify -u https://example.com/hooks' + ] + + static flags = { + app: flags.app(), + remote: flags.remote(), + pipeline: flags.pipeline({char: 'p', description: 'pipeline on which to list', hidden: true}), + include: flags.string({char: 'i', description: 'comma delimited event types your server will receive ', required: true}), + level: flags.string({char: 'l', description: 'notify does not retry, sync will retry until successful or timeout', required: true}), + secret: flags.string({char: 's', description: 'value to sign delivery with in Heroku-Webhook-Hmac-SHA256 header'}), + authorization: flags.string({char: 't', description: 'authoriation header to send with webhooks'}), + url: flags.string({char: 'u', description: 'URL for receiver', required: true}) + } + + async run() { + const {flags} = this.parse(WebhooksAdd) + const {path, display} = this.webhookType(flags) + + cli.action.start(`Adding webhook to ${display}`) + + const response = await this.webhooksClient.post(`${path}/webhooks`, { + body: { + include: flags.include.split(',').map(s => s.trim()), + level: flags.level, + secret: flags.secret, + url: flags.url, + authorization: flags.authorization + } + }) + + const secret = response.headers && response.headers['heroku-webhook-secret'] as string + + cli.action.stop() + + if (secret) { + cli.styledHeader('Webhooks Signing Secret') + this.log(secret) + } else { + cli.warn('no secret found') + } + } +} diff --git a/packages/webhooks/src/commands/webhooks/deliveries/index.ts b/packages/webhooks/src/commands/webhooks/deliveries/index.ts new file mode 100644 index 0000000000..39974b03f4 --- /dev/null +++ b/packages/webhooks/src/commands/webhooks/deliveries/index.ts @@ -0,0 +1,84 @@ +import {flags} from '@heroku-cli/command' +import {cli} from 'cli-ux' + +import BaseCommand from '../../base' + +export default class Deliveries extends BaseCommand { + static description = 'list webhook deliveries on an app' + + static examples = [ + '$ heroku webhooks:deliveries' + ] + + static flags = { + app: flags.app(), + remote: flags.remote(), + status: flags.string({char: 's', description: 'filter deliveries by status'}), + pipeline: flags.pipeline({char: 'p', description: 'pipeline on which to list', hidden: true}) + } + + async run() { + const {flags} = this.parse(Deliveries) + let {path, display} = this.webhookType(flags) + const max = 1000 + + path = `${path}/webhook-deliveries` + if (flags.status) { + path += `?eq[status]=${encodeURIComponent(flags.status)}` + } + + const {body: deliveries} = await this.webhooksClient.get(path, { + headers: { + Range: `seq ..; order=desc,max=${max}` + }, + partial: true + }) + + if (deliveries.length === 0) { + this.log(`${display} has no deliveries`) + } else { + let code = (w: any) => { + return (w.last_attempt && w.last_attempt.code && String(w.last_attempt.code)) || '' + } + + deliveries.reverse() + + if (deliveries.length === max) { + this.warn(`Only showing the ${max} most recent deliveries`) + this.warn('It is possible to filter deliveries by using the --status flag') + } + + cli.table(deliveries, { + id: { + header: 'Delivery ID' + }, + created_at: { + header: 'Created', get: (w: any) => w.created_at + }, + status: { + get: (w: any) => w.status + }, + include: { + get: (w: any) => w.event.include + }, + level: { + get: (w: any) => w.webhook.level + }, + num_attempts: { + header: 'Attempts', get: (w: any) => String(w.num_attempts) + }, + last_code: { + header: 'Code', get: code + }, + last_error: { + header: 'Error', get: (w: any) => (w.last_attempt && w.last_attempt.error_class) || '' + }, + next_attempt_at: { + header: 'Next Attempt', get: (w: any) => w.next_attempt_at || '' + }, + }, { + printLine: this.log + }) + } + } +} diff --git a/packages/webhooks/src/commands/webhooks/deliveries/info.ts b/packages/webhooks/src/commands/webhooks/deliveries/info.ts new file mode 100644 index 0000000000..70f6e06bb4 --- /dev/null +++ b/packages/webhooks/src/commands/webhooks/deliveries/info.ts @@ -0,0 +1,50 @@ +import {flags} from '@heroku-cli/command' +import {cli} from 'cli-ux' + +import BaseCommand from '../../base' + +export default class DeliveriesInfo extends BaseCommand { + static description = 'info for a webhook event on an app' + + static examples = [ + '$ heroku webhooks:deliveries:info 99999999-9999-9999-9999-999999999999' + ] + + static flags = { + app: flags.app(), + remote: flags.remote(), + pipeline: flags.pipeline({char: 'p', description: 'pipeline on which to list', hidden: true}) + } + + static args = [ + {name: 'id', required: true} + ] + + async run() { + const {flags, args} = this.parse(DeliveriesInfo) + const {path} = this.webhookType(flags) + + const {body: delivery} = await this.webhooksClient.get(`${path}/webhook-deliveries/${args.id}`) + + const {body: event} = await this.webhooksClient.get(`${path}/webhook-events/${delivery.event.id}`) + + const obj = { + Created: delivery.created_at, + Event: delivery.event.id, + Webhook: delivery.webhook.id, + Status: delivery.status, + Include: delivery.event.include, + Level: delivery.webhook.level, + Attempts: delivery.num_attempts, + Code: delivery.last_attempt && delivery.last_attempt.code, + Error: delivery.last_attempt && delivery.last_attempt.error_class, + 'Next Attempt': delivery.next_attempt_at + } + + cli.styledHeader(delivery.id) + cli.styledObject(obj) + + cli.styledHeader('Event Payload') + cli.styledJSON(event.payload) + } +} diff --git a/packages/webhooks/src/commands/webhooks/events/index.ts b/packages/webhooks/src/commands/webhooks/events/index.ts new file mode 100644 index 0000000000..ebfeb24cc9 --- /dev/null +++ b/packages/webhooks/src/commands/webhooks/events/index.ts @@ -0,0 +1,50 @@ +import {flags} from '@heroku-cli/command' +import {cli} from 'cli-ux' + +import BaseCommand from '../../base' + +export default class EventsIndex extends BaseCommand { + static description = 'list webhook events on an app' + + static examples = [ + '$ heroku webhooks:events' + ] + + static flags = { + app: flags.app(), + remote: flags.remote(), + pipeline: flags.pipeline({char: 'p', description: 'pipeline on which to list', hidden: true}) + } + + async run() { + const {flags} = this.parse(EventsIndex) + const {path, display} = this.webhookType(flags) + + cli.warn('heroku webhooks:event is deprecated, please use heroku webhooks:deliveries') + + const {body: events} = await this.webhooksClient.get(`${path}/webhook-events`) + + if (events.length === 0) { + this.log(`${display} has no events`) + } else { + events.sort((a: any, b: any) => Date.parse(a.created_at) - Date.parse(b.created_at)) + + cli.table(events, { + id: { + header: 'Event ID' + }, + resource: { + get: (w: any) => w.payload.resource + }, + action: { + get: (w: any) => w.payload.action + }, + published_at: { + header: 'Published At', get: (w: any) => w.payload.published_at + } + }, { + printLine: this.log + }) + } + } +} diff --git a/packages/webhooks/src/commands/webhooks/events/info.ts b/packages/webhooks/src/commands/webhooks/events/info.ts new file mode 100644 index 0000000000..40cd6c77c1 --- /dev/null +++ b/packages/webhooks/src/commands/webhooks/events/info.ts @@ -0,0 +1,38 @@ +import {flags} from '@heroku-cli/command' +import {cli} from 'cli-ux' + +import BaseCommand from '../../base' + +export default class Info extends BaseCommand { + static description = 'info for a webhook event on an app' + + static examples = [ + '$ heroku webhooks:events:info 99999999-9999-9999-9999-999999999999' + ] + + static flags = { + app: flags.app(), + remote: flags.remote(), + pipeline: flags.pipeline({char: 'p', description: 'pipeline on which to list', hidden: true}) + } + + static args = [ + {name: 'id', required: true} + ] + + async run() { + const {flags, args} = this.parse(Info) + const {path} = this.webhookType(flags) + + cli.warn('heroku webhooks:event:info is deprecated, please use heroku webhooks:deliveries:info') + + const {body: webhookEvent} = await this.webhooksClient.get(`${path}/webhook-events/${args.id}`) + + const obj = { + payload: JSON.stringify(webhookEvent.payload, null, 2) + } + + cli.styledHeader(webhookEvent.id) + cli.styledObject(obj) + } +} diff --git a/packages/webhooks/src/commands/webhooks/index.ts b/packages/webhooks/src/commands/webhooks/index.ts new file mode 100644 index 0000000000..1629824c12 --- /dev/null +++ b/packages/webhooks/src/commands/webhooks/index.ts @@ -0,0 +1,51 @@ +import color from '@heroku-cli/color' +import {flags} from '@heroku-cli/command' +import {cli} from 'cli-ux' + +import BaseCommand from '../base' + +export default class Webhooks extends BaseCommand { + static description = 'list webhooks on an app' + + static examples = ['$ heroku webhooks'] + + static flags = { + app: flags.app(), + remote: flags.remote(), + pipeline: flags.pipeline({ + char: 'p', + description: + 'pipeline on which to list', + hidden: true + }) + } + + async run() { + const {flags} = this.parse(Webhooks) + const {path, display} = this.webhookType(flags) + + const {body: webhooks} = await this.webhooksClient.get(`${path}/webhooks`) + + if (webhooks.length === 0) { + this.log(`${display} has no webhooks\nUse ${color.cmd('heroku webhooks:add')} to add one.`) + return + } + + webhooks.sort((a: any, b: any) => Date.parse(a.created_at) - Date.parse(b.created_at)) + + cli.table(webhooks, { + id: { + header: 'Webhook ID' + }, + url: { + header: 'URL' + }, + include: { + get: (row: any) => row.include.join(',') + }, + level: {} + }, { + printLine: this.log + }) + } +} diff --git a/packages/webhooks/src/commands/webhooks/info.ts b/packages/webhooks/src/commands/webhooks/info.ts new file mode 100644 index 0000000000..96add04610 --- /dev/null +++ b/packages/webhooks/src/commands/webhooks/info.ts @@ -0,0 +1,35 @@ +import {flags} from '@heroku-cli/command' +import {cli} from 'cli-ux' + +import BaseCommand from '../base' + +export default class WebhooksInfo extends BaseCommand { + static description = 'info for a webhook on an app' + + static example = ['$ heroku webhooks:info 99999999-9999-9999-9999-999999999999'] + + static flags = { + app: flags.app(), + remote: flags.remote(), + pipeline: flags.pipeline({char: 'p', description: 'pipeline on which to list', hidden: true}) + } + + static args = [{name: 'id', required: true}] + + async run() { + const {flags, args} = this.parse(WebhooksInfo) + const {path} = this.webhookType(flags) + + const {body: webhook} = await this.webhooksClient.get(`${path}/webhooks/${args.id}`) + + const obj = { + 'Webhook ID': webhook.id, + URL: webhook.url, + Include: webhook.include.join(','), + Level: webhook.level + } + + cli.styledHeader(webhook.id) + cli.styledObject(obj) + } +} diff --git a/packages/webhooks/src/commands/webhooks/remove.ts b/packages/webhooks/src/commands/webhooks/remove.ts new file mode 100644 index 0000000000..6d71af7ab4 --- /dev/null +++ b/packages/webhooks/src/commands/webhooks/remove.ts @@ -0,0 +1,32 @@ +import {flags} from '@heroku-cli/command' +import {cli} from 'cli-ux' + +import BaseCommand from '../base' +export default class WebhooksRemove extends BaseCommand { + static description = 'removes a webhook from an app' + + static examples = [ + '$ heroku webhooks:remove 99999999-9999-9999-9999-999999999999' + ] + + static flags = { + app: flags.app(), + remote: flags.remote(), + pipeline: flags.pipeline({char: 'p', description: 'pipeline on which to list', hidden: true}) + } + + static args = [ + {name: 'id', description: 'id of webhook to remove', required: true} + ] + + async run() { + const {flags, args} = this.parse(WebhooksRemove) + const {path, display} = this.webhookType(flags) + + cli.action.start(`Removing webhook ${args.id} from ${display}`) + + await this.webhooksClient.delete(`${path}/webhooks/${args.id}`) + + cli.action.stop() + } +} diff --git a/packages/webhooks/src/commands/webhooks/update.ts b/packages/webhooks/src/commands/webhooks/update.ts new file mode 100644 index 0000000000..2958ec6aed --- /dev/null +++ b/packages/webhooks/src/commands/webhooks/update.ts @@ -0,0 +1,45 @@ +import {flags} from '@heroku-cli/command' +import {cli} from 'cli-ux' + +import BaseCommand from '../base' + +export default class WebhooksUpdate extends BaseCommand { + static description = 'updates a webhook in an app' + + static examples = [ + '$ heroku webhooks:update 99999999-9999-9999-9999-999999999999 -i dyno -l notify -s 09928c40bf1b191b645174a19f7053d16a180da37332e719ef0998f4c0a2 -u https://example.com/hooks' + ] + + static flags = { + app: flags.app(), + remote: flags.remote(), + pipeline: flags.pipeline({char: 'p', description: 'pipeline on which to list', hidden: true}), + include: flags.string({char: 'i', description: 'comma delimited event types your server will receive ', required: true}), + level: flags.string({char: 'l', description: 'notify does not retry, sync will retry until successful or timeout', required: true}), + secret: flags.string({char: 's', description: 'value to sign delivery with in Heroku-Webhook-Hmac-SHA256 header'}), + authorization: flags.string({char: 't', description: 'authoriation header to send with webhooks'}), + url: flags.string({char: 'u', description: 'URL for receiver', required: true}) + } + + static args = [ + {name: 'id', required: true} + ] + + async run() { + const {flags, args} = this.parse(WebhooksUpdate) + const {path, display} = this.webhookType(flags) + + cli.action.start(`Updating webhook ${args.id} for ${display}`) + + await this.webhooksClient.patch(`${path}/webhooks/${args.id}`, { + body: { + include: flags.include && flags.include.split(',').map(s => s.trim()), + level: flags.level, + secret: flags.secret, + url: flags.url + } + }) + + cli.action.stop() + } +} diff --git a/packages/webhooks/src/index.ts b/packages/webhooks/src/index.ts new file mode 100644 index 0000000000..b1c6ea436a --- /dev/null +++ b/packages/webhooks/src/index.ts @@ -0,0 +1 @@ +export default {} diff --git a/packages/webhooks/test/commands/base.test.ts b/packages/webhooks/test/commands/base.test.ts new file mode 100644 index 0000000000..58def7e622 --- /dev/null +++ b/packages/webhooks/test/commands/base.test.ts @@ -0,0 +1,41 @@ +import {Config, IConfig} from '@oclif/config' +import {expect, test} from '@oclif/test' +import * as path from 'path' + +import webhooksAbstractClass from '../../src/commands/base' + +class Webhooks extends webhooksAbstractClass { + constructor(argv: string[], config: IConfig) { + super(argv, config) + } + async run() {} +} +const root = path.resolve(__dirname, '../package.json') +const config = new Config({root}) +const webhookObject = new Webhooks([], config) + +describe('webhooks type', () => { + test + .stdout() + .do(function () { + const webhookInfo = webhookObject.webhookType({pipeline: 'randomPipeline', app: ''}) + expect(webhookInfo).to.deep.equal({path: '/pipelines/randomPipeline', display: 'randomPipeline'}) + }) + .it('returns correct pipeline path and display info') + + test + .stdout() + .do(function () { + const webhookInfo = webhookObject.webhookType({pipeline: '', app: 'randomApp'}) + expect(webhookInfo).to.deep.equal({path: '/apps/randomApp', display: 'randomApp'}) + }) + .it('returns correct app path and display info') + + test + .stdout() + .do(function () { + webhookObject.webhookType({pipeline: '', app: ''}) + }) + .catch(e => expect(e.message).to.equal('No app specified')) + .it('returns error if no arguments are given') +}) diff --git a/packages/webhooks/test/commands/webhooks/add.test.ts b/packages/webhooks/test/commands/webhooks/add.test.ts new file mode 100644 index 0000000000..3cdbdb2a05 --- /dev/null +++ b/packages/webhooks/test/commands/webhooks/add.test.ts @@ -0,0 +1,76 @@ +import {expect, test} from '@oclif/test' + +describe('webhooks:add', () => { + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .post('/apps/example-app/webhooks', { + include: ['foo', 'bar'], + level: 'notify', + secret: '1234', + url: 'http://foobar.com' + }) + .reply(200, {}) + ) + .command([ + 'webhooks:add', + '--app', 'example-app', + '--include', 'foo,bar', + '--secret', '1234', + '--level', 'notify', + '--url', 'http://foobar.com' + ]) + .it('adds a specific app webhook', ctx => { + expect(ctx.stdout).to.equal('') + expect(ctx.stderr).to.contain('Adding webhook to example-app... done\n') + }) + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .post('/pipelines/example-pipeline/webhooks', { + include: ['foo', 'bar'], + level: 'notify', + secret: '1234', + url: 'http://foobar.com' + }) + .reply(200, {}) + ) + .command([ + 'webhooks:add', + '--pipeline', 'example-pipeline', + '--include', 'foo,bar', + '--secret', '1234', + '--level', 'notify', + '--url', 'http://foobar.com' + ]) + .it('adds a specific pipeline webhook', ctx => { + expect(ctx.stdout).to.equal('') + expect(ctx.stderr).to.contain('Adding webhook to example-pipeline... done\n') + }) + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .post('/pipelines/example-pipeline/webhooks', { + include: ['foo', 'bar'], + level: 'notify', + url: 'http://foobar.com' + }) + .reply(200, {}, {'heroku-webhook-secret': '1234'}) + ) + .command([ + 'webhooks:add', + '--pipeline', 'example-pipeline', + '--include', 'foo,bar', + '--level', 'notify', + '--url', 'http://foobar.com' + ]) + .it('adds a specific pipeline webhook', ctx => { + expect(ctx.stdout).to.equal('=== Webhooks Signing Secret\n1234\n') + expect(ctx.stderr).to.contain('Adding webhook to example-pipeline... done\n') + }) +}) diff --git a/packages/webhooks/test/commands/webhooks/deliveries/index.test.ts b/packages/webhooks/test/commands/webhooks/deliveries/index.test.ts new file mode 100644 index 0000000000..83a2a42c20 --- /dev/null +++ b/packages/webhooks/test/commands/webhooks/deliveries/index.test.ts @@ -0,0 +1,217 @@ +import {expect, test} from '@oclif/test' + +describe('webhooks:deliveries', () => { + describe('app webhooks', () => { + test + .stdout() + .stderr() + .nock('https://api.heroku.com', { + reqheaders: {range: 'seq ..; order=desc,max=1000'} + }, api => api + .get('/apps/example-app/webhook-deliveries') + .reply(206, [ + { + id: '66666666-6666-6666-6666-666666666666', + event: { + id: '55555555-5555-5555-5555-555555555555', + include: 'api:build' + }, + webhook: { + id: '44444444-4444-4444-4444-444444444444', + level: 'notify' + }, + status: 'pending', + num_attempts: 4, + created_at: '2017-08-17T20:22:38Z' + }, + { + id: '99999999-9999-9999-9999-999999999999', + event: { + id: '88888888-8888-8888-8888-888888888888', + include: 'api:build' + }, + webhook: { + id: '77777777-7777-7777-7777-777777777777', + level: 'notify' + }, + last_attempt: { + code: 401, + error_class: 'Foobar' + }, + status: 'retrying', + num_attempts: 4, + created_at: '2017-08-17T20:22:37Z', + next_attempt_at: '2017-08-17T20:22:39Z' + } + ]) + ) + .command(['webhooks:deliveries', '--app', 'example-app']) + .it('lists webhooks deliveries for app webhooks', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout.trim()).to.equal( + `Delivery ID Created Status Include Level Attempts Code Error Next Attempt +99999999-9999-9999-9999-999999999999 2017-08-17T20:22:37Z retrying api:build notify 4 401 Foobar 2017-08-17T20:22:39Z +66666666-6666-6666-6666-666666666666 2017-08-17T20:22:38Z pending api:build notify 4`) + }) + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', { + reqheaders: {range: 'seq ..; order=desc,max=1000'} + }, api => api + .get('/apps/example-app/webhook-deliveries?eq[status]=pending') + .reply(206, [ + { + id: '66666666-6666-6666-6666-666666666666', + event: { + id: '55555555-5555-5555-5555-555555555555', + include: 'api:build' + }, + webhook: { + id: '44444444-4444-4444-4444-444444444444', + level: 'notify' + }, + status: 'pending', + num_attempts: 4, + created_at: '2017-08-17T20:22:38Z' + } + ]) + ) + .command(['webhooks:deliveries', '--app', 'example-app', '--status', 'pending']) + .it('lists webhook deliveries for app webhooks filtered by status', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout.trim()).to.equal( + `Delivery ID Created Status Include Level Attempts Code Error Next Attempt +66666666-6666-6666-6666-666666666666 2017-08-17T20:22:38Z pending api:build notify 4`) + }) + + test + .stderr() + .stdout() + .nock('https://api.heroku.com', { + reqheaders: {range: 'seq ..; order=desc,max=1000'} + }, api => api + .get('/apps/example-app/webhook-deliveries') + .reply(206, () => { + let delivery = { + id: '66666666-6666-6666-6666-666666666666', + event: { + id: '55555555-5555-5555-5555-555555555555', + include: 'api:build' + }, + webhook: { + id: '44444444-4444-4444-4444-444444444444', + level: 'notify' + }, + status: 'pending', + num_attempts: 4, + created_at: '2017-08-17T20:22:38Z' + } + + return new Array(1000).fill(delivery) + }) + ) + .command(['webhooks:deliveries', '--app', 'example-app']) + .it('only shows 1000 webhook deliveries', ctx => { + let expectedHeader = 'Delivery ID Created Status Include Level Attempts Code Error Next Attempt' + let expectedRow = '66666666-6666-6666-6666-666666666666 2017-08-17T20:22:38Z pending api:build notify 4' + let angleBrackets = process.platform === 'win32' ? '»' : '›' + const rows = ctx.stdout.split('\n') + + const headerRowCount = 1 + const dataRowsCount = 1000 + const finalTrailingRowCount = 1 + expect(rows.length).to.equal(headerRowCount + dataRowsCount + finalTrailingRowCount) + + expect(rows[0].trim()).to.equal(expectedHeader) + expect(rows[1].trim()).to.equal(expectedRow) + + expect(ctx.stderr).to.include(` ${angleBrackets} Warning: Only showing the 1000 most recent deliveries\n ${angleBrackets} Warning: It is possible to filter deliveries by using the --status flag\n`) + }) + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', { + reqheaders: {range: 'seq ..; order=desc,max=1000'} + }, api => api + .get('/apps/example-app/webhook-deliveries') + .reply(200, []) + ) + .command(['webhooks:deliveries', '--app', 'example-app']) + .it('lists empty deliveries', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout.trim()).to.equal('example-app has no deliveries') + }) + }) + + describe('pipeline webhooks', () => { + test + .stdout() + .stderr() + .nock('https://api.heroku.com', { + reqheaders: {range: 'seq ..; order=desc,max=1000'} + }, api => api + .get('/pipelines/example-pipeline/webhook-deliveries') + .reply(206, [ + { + id: '66666666-6666-6666-6666-666666666666', + event: { + id: '55555555-5555-5555-5555-555555555555', + include: 'api:build' + }, + webhook: { + id: '44444444-4444-4444-4444-444444444444', + level: 'notify' + }, + status: 'pending', + num_attempts: 4, + created_at: '2017-08-17T20:22:38Z' + }, + { + id: '99999999-9999-9999-9999-999999999999', + event: { + id: '88888888-8888-8888-8888-888888888888', + include: 'api:build' + }, + webhook: { + id: '77777777-7777-7777-7777-777777777777', + level: 'notify' + }, + last_attempt: { + code: 401, + error_class: 'Foobar' + }, + status: 'retrying', + num_attempts: 4, + created_at: '2017-08-17T20:22:37Z', + next_attempt_at: '2017-08-17T20:22:39Z' + } + ]) + ) + .command(['webhooks:deliveries', '--pipeline', 'example-pipeline']) + .it('lists webhooks deliveries for pipeline webhooks', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout.trim()).to.equal( + `Delivery ID Created Status Include Level Attempts Code Error Next Attempt +99999999-9999-9999-9999-999999999999 2017-08-17T20:22:37Z retrying api:build notify 4 401 Foobar 2017-08-17T20:22:39Z +66666666-6666-6666-6666-666666666666 2017-08-17T20:22:38Z pending api:build notify 4`) + }) + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', { + reqheaders: {range: 'seq ..; order=desc,max=1000'} + }, api => api + .get('/pipelines/example-pipeline/webhook-deliveries') + .reply(200, []) + ) + .command(['webhooks:deliveries', '--pipeline', 'example-pipeline']) + .it('lists empty webhooks deliveries for pipeline webhooks', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout.trim()).to.equal('example-pipeline has no deliveries') + }) + }) +}) diff --git a/packages/webhooks-v5/test/commands/webhooks/deliveries/info.js b/packages/webhooks/test/commands/webhooks/deliveries/info.test.ts similarity index 54% rename from packages/webhooks-v5/test/commands/webhooks/deliveries/info.js rename to packages/webhooks/test/commands/webhooks/deliveries/info.test.ts index dc7c63fb7c..981e8c052b 100644 --- a/packages/webhooks-v5/test/commands/webhooks/deliveries/info.js +++ b/packages/webhooks/test/commands/webhooks/deliveries/info.test.ts @@ -1,20 +1,11 @@ -/* eslint-disable camelcase */ -'use strict' -/* globals describe it beforeEach cli */ +import { expect, test } from '@oclif/test' -let expect = require('chai').expect -let nock = require('nock') -let certs = require('../../../../commands/webhooks/deliveries/info') - -describe('heroku webhooks:deliveries:info', function () { - beforeEach(function () { - cli.mockConsole() - nock.cleanAll() - }) - - it('# shows a delivery', function () { - let mockDelivery = nock('https://api.heroku.com') - .get('/apps/example/webhook-deliveries/99999999-9999-9999-9999-999999999999') +describe('webhooks:deliveries:info', () => { + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get('/apps/example-app/webhook-deliveries/99999999-9999-9999-9999-999999999999') .reply(200, { id: '99999999-9999-9999-9999-999999999999', event: { @@ -25,9 +16,9 @@ describe('heroku webhooks:deliveries:info', function () { }, status: 'pending' }) - - let mockEvent = nock('https://api.heroku.com') - .get('/apps/example/webhook-events/88888888-8888-8888-8888-888888888888') + ) + .nock('https://api.heroku.com', api => api + .get('/apps/example-app/webhook-events/88888888-8888-8888-8888-888888888888') .reply(200, { id: '88888888-8888-8888-8888-888888888888', payload: { @@ -39,12 +30,15 @@ describe('heroku webhooks:deliveries:info', function () { } } }) - - return certs.run(['99999999-9999-9999-9999-999999999999', '--app', 'example']).then(function () { - mockDelivery.done() - mockEvent.done() - expect(cli.stderr).to.equal('') - expect(cli.stdout).to.equal( + ) + .command([ + 'webhooks:deliveries:info', + '--app', 'example-app', + '99999999-9999-9999-9999-999999999999' + ]) + .it('shows an app webhook delivery', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout).to.equal( `=== 99999999-9999-9999-9999-999999999999 Event: 88888888-8888-8888-8888-888888888888 Status: pending @@ -60,11 +54,12 @@ Webhook: 77777777-7777-7777-7777-777777777777 } `) }) - }) - it('# shows a delivery (piplines)', function () { - let mockDelivery = nock('https://api.heroku.com') - .get('/pipelines/example/webhook-deliveries/99999999-9999-9999-9999-999999999999') + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get('/pipelines/example-pipeline/webhook-deliveries/99999999-9999-9999-9999-999999999999') .reply(200, { id: '99999999-9999-9999-9999-999999999999', event: { @@ -75,9 +70,9 @@ Webhook: 77777777-7777-7777-7777-777777777777 }, status: 'pending' }) - - let mockEvent = nock('https://api.heroku.com') - .get('/pipelines/example/webhook-events/88888888-8888-8888-8888-888888888888') + ) + .nock('https://api.heroku.com', api => api + .get('/pipelines/example-pipeline/webhook-events/88888888-8888-8888-8888-888888888888') .reply(200, { id: '88888888-8888-8888-8888-888888888888', payload: { @@ -89,12 +84,15 @@ Webhook: 77777777-7777-7777-7777-777777777777 } } }) - - return certs.run(['99999999-9999-9999-9999-999999999999', '--pipeline', 'example']).then(function () { - mockDelivery.done() - mockEvent.done() - expect(cli.stderr).to.equal('') - expect(cli.stdout).to.equal( + ) + .command([ + 'webhooks:deliveries:info', + '--pipeline', 'example-pipeline', + '99999999-9999-9999-9999-999999999999' + ]) + .it('shows a pipeline webhook delivery ', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout).to.equal( `=== 99999999-9999-9999-9999-999999999999 Event: 88888888-8888-8888-8888-888888888888 Status: pending @@ -110,5 +108,4 @@ Webhook: 77777777-7777-7777-7777-777777777777 } `) }) - }) }) diff --git a/packages/webhooks/test/commands/webhooks/events/index.test.ts b/packages/webhooks/test/commands/webhooks/events/index.test.ts new file mode 100644 index 0000000000..43289134e3 --- /dev/null +++ b/packages/webhooks/test/commands/webhooks/events/index.test.ts @@ -0,0 +1,147 @@ +import {expect, test} from '@oclif/test' +import { addDays, parse } from 'date-fns' + +describe('webhooks:events', () => { + const deprecationWarning = 'Warning: heroku webhooks:event is deprecated, please use heroku webhooks:deliveries\n' + + describe('app webhooks', () => { + const appWebhookEventsPath = '/apps/example-app/webhook-events' + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get(appWebhookEventsPath) + .reply(200, [{ + id: '99999999-9999-9999-9999-999999999999', + payload: { + published_at: '2016-08-31T21:55:06Z', + resource: 'api:release', + action: 'create' + } + }]) + ) + .command(['webhooks:events', '--app', 'example-app']) + .it('lists app webhook events', ctx => { + expect(ctx.stderr).to.include(deprecationWarning) + expect(ctx.stdout).to.equal(`Event ID Resource Action Published At +99999999-9999-9999-9999-999999999999 api:release create 2016-08-31T21:55:06Z +`) + }) + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get(appWebhookEventsPath) + .reply(200, []) + ) + .command(['webhooks:events', '--app', 'example-app']) + .it('displays an empty events message', ctx => { + expect(ctx.stderr).to.include(deprecationWarning) + expect(ctx.stdout).to.equal('example-app has no events\n') + }) + }) + + describe('pipeline webhooks', () => { + const pipelineWebhookEventsPath = '/pipelines/example-pipeline/webhook-events' + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get(pipelineWebhookEventsPath) + .reply(200, [{ + id: '99999999-9999-9999-9999-999999999999', + payload: { + published_at: '2016-08-31T21:55:06Z', + resource: 'api:release', + action: 'create' + } + }]) + ) + .command(['webhooks:events', '--pipeline', 'example-pipeline']) + .it('lists pipeline webhook events', ctx => { + expect(ctx.stderr).to.include(deprecationWarning) + expect(ctx.stdout).to.equal(`Event ID Resource Action Published At +99999999-9999-9999-9999-999999999999 api:release create 2016-08-31T21:55:06Z +`) + }) + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get(pipelineWebhookEventsPath) + .reply(200, []) + ) + .command(['webhooks:events', '--pipeline', 'example-pipeline']) + .it('displays an empty events message', ctx => { + expect(ctx.stderr).to.include(deprecationWarning) + expect(ctx.stdout).to.equal('example-pipeline has no events\n') + }) + }) + + describe('by default the table is sorted by `created_at`', () => { + const firstDate = parse('2019-06-11T14:20:42Z') + const secondDate = addDays(parse(firstDate), 1) + const thirdDate = addDays(parse(firstDate), 2) + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get('/apps/example-app/webhook-events') + .reply(200, [ + // the returned ordered from the api is not ordered by + // `created_at` but the results displayed by the cli + // in thae table *are* ordered by `created_at` + + // first date + { + id: '00000000-0000-0000-0000-000000000000', + created_at: firstDate.toISOString(), + payload: { + published_at: '2019-06-15T14:20:42Z', + resource: 'api:release', + action: 'create' + } + }, + + // third date + { + id: '11111111-1111-1111-1111-111111111111', + created_at: thirdDate.toISOString(), + payload: { + published_at: '2019-06-15T14:20:42Z', + resource: 'api:release', + action: 'create' + } + }, + + // second date + { + id: '22222222-2222-2222-2222-222222222222', + created_at: secondDate.toISOString(), + payload: { + published_at: '2019-06-15T14:20:42Z', + resource: 'api:release', + action: 'create' + } + } + ]) + ) + .command(['webhooks:events', '--app', 'example-app']) + .it('displays webhooks sorted by `created_at`', ctx => { + expect(ctx.stderr).to.include(deprecationWarning) + + // Note: The table is sorted by `created_at` date even though + // it is not displayed in the table + expect(ctx.stdout).to.equal(`Event ID Resource Action Published At +00000000-0000-0000-0000-000000000000 api:release create 2019-06-15T14:20:42Z +22222222-2222-2222-2222-222222222222 api:release create 2019-06-15T14:20:42Z +11111111-1111-1111-1111-111111111111 api:release create 2019-06-15T14:20:42Z +`) + }) + }) +}) diff --git a/packages/webhooks/test/commands/webhooks/events/info.test.ts b/packages/webhooks/test/commands/webhooks/events/info.test.ts new file mode 100644 index 0000000000..2a6c1b685d --- /dev/null +++ b/packages/webhooks/test/commands/webhooks/events/info.test.ts @@ -0,0 +1,77 @@ +import {expect, test} from '@oclif/test' + +describe('webhooks:events:info', () => { + const deprecationWarning = 'Warning: heroku webhooks:event:info is deprecated, please use heroku webhooks:deliveries:info\n' + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get('/apps/example-app/webhook-events/99999999-9999-9999-9999-999999999999') + .reply(200, { + id: '99999999-9999-9999-9999-999999999999', + payload: { + published_at: '2016-08-31T21:55:06Z', + resource: 'api:release', + action: 'create', + data: { + foo: 'bar' + } + } + }) + ) + .command([ + 'webhooks:events:info', + '--app', 'example-app', + '99999999-9999-9999-9999-999999999999' + ]) + .it('lists webhooks events info for app webhooks', ctx => { + expect(ctx.stderr).to.include(deprecationWarning) + expect(ctx.stdout).to.equal(`=== 99999999-9999-9999-9999-999999999999 +payload: { + "published_at": "2016-08-31T21:55:06Z", + "resource": "api:release", + "action": "create", + "data": { + "foo": "bar" + } +} +`) + }) + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get('/pipelines/example-pipeline/webhook-events/99999999-9999-9999-9999-999999999999') + .reply(200, { + id: '99999999-9999-9999-9999-999999999999', + payload: { + published_at: '2016-08-31T21:55:06Z', + resource: 'api:release', + action: 'create', + data: { + foo: 'bar' + } + } + }) + ) + .command([ + 'webhooks:events:info', + '--pipeline', 'example-pipeline', + '99999999-9999-9999-9999-999999999999' + ]) + .it('lists webhooks events info for pipeline webhooks', ctx => { + expect(ctx.stderr).to.include(deprecationWarning) + expect(ctx.stdout).to.equal(`=== 99999999-9999-9999-9999-999999999999 +payload: { + "published_at": "2016-08-31T21:55:06Z", + "resource": "api:release", + "action": "create", + "data": { + "foo": "bar" + } +} +`) + }) +}) diff --git a/packages/webhooks/test/commands/webhooks/index.test.ts b/packages/webhooks/test/commands/webhooks/index.test.ts new file mode 100644 index 0000000000..8d9d07e9cf --- /dev/null +++ b/packages/webhooks/test/commands/webhooks/index.test.ts @@ -0,0 +1,132 @@ +import { expect, test } from '@oclif/test' +import { addDays, parse } from 'date-fns' + +describe('webhooks:index', () => { + describe('app webhooks', () => { + let appWebhooksUrl = '/apps/example/webhooks' + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get(appWebhooksUrl) + .reply(200, [{ + id: '99999999-9999-9999-9999-999999999999', + include: ['foo', 'bar'], + level: 'notify', + url: 'http://foobar.com' + }]) + ) + .command(['webhooks', '--app', 'example']) + .it('lists webhooks', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout).to.equal(`Webhook ID URL Include Level +99999999-9999-9999-9999-999999999999 http://foobar.com foo,bar notify +`) + }) + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get(appWebhooksUrl) + .reply(200, []) + ) + .command(['webhooks', '--app', 'example']) + .it('displays a "no webhooks" message', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout).to.equal('example has no webhooks\nUse heroku webhooks:add to add one.\n') + }) + }) + + describe('pipeline webhooks', () => { + let pipelinesWebhooksUrl = '/pipelines/example/webhooks' + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get(pipelinesWebhooksUrl) + .reply(200, [{ + id: '99999999-9999-9999-9999-999999999999', + include: ['foo', 'bar'], + level: 'notify', + url: 'http://foobar.com' + }]) + ) + .command(['webhooks', '--pipeline', 'example']) + .it('lists webhooks', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout).to.equal(`Webhook ID URL Include Level +99999999-9999-9999-9999-999999999999 http://foobar.com foo,bar notify +`) + }) + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get(pipelinesWebhooksUrl) + .reply(200, []) + ) + .command(['webhooks', '--pipeline', 'example']) + .it('displays a "no webhooks" message', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout).to.equal('example has no webhooks\nUse heroku webhooks:add to add one.\n') + }) + }) + + describe('by default the table is sorted by `created_at`', () => { + let firstDate = parse('2019-06-11T14:20:42Z') + let secondDate = addDays(parse(firstDate), 1) + let thirdDate = addDays(parse(firstDate), 2) + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get('/apps/example/webhooks') + .reply(200, [ + // the returned ordered from the api is not ordered by + // `created_at` but the results displayed by the cli + // in thae table *are* ordered by `created_at` + + // first date + { + created_at: firstDate.toISOString(), + id: '00000000-0000-0000-0000-000000000000', + include: ['api:release'], + level: 'sync', + url: 'https://test.com/hook' + }, + + // third date + { + created_at: thirdDate.toISOString(), + id: '11111111-1111-1111-1111-111111111111', + include: ['api:release'], + level: 'sync', + url: 'https://test.com/hook' + }, + + // second date + { + created_at: secondDate.toISOString(), + id: '22222222-2222-2222-2222-222222222222', + include: ['api:release'], + level: 'sync', + url: 'https://test.com/hook' + } + ]) + ) + .command(['webhooks', '--app', 'example']) + .it('displays webhooks sorted by `created_at`', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout).to.equal(`Webhook ID URL Include Level +00000000-0000-0000-0000-000000000000 https://test.com/hook api:release sync +22222222-2222-2222-2222-222222222222 https://test.com/hook api:release sync +11111111-1111-1111-1111-111111111111 https://test.com/hook api:release sync +`) + }) + }) +}) diff --git a/packages/webhooks/test/commands/webhooks/info.test.ts b/packages/webhooks/test/commands/webhooks/info.test.ts new file mode 100644 index 0000000000..34c91171f8 --- /dev/null +++ b/packages/webhooks/test/commands/webhooks/info.test.ts @@ -0,0 +1,49 @@ +import {expect, test} from '@oclif/test' + +describe('webhooks:info', () => { + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get('/apps/example-app/webhooks/99999999-9999-9999-9999-999999999999') + .reply(200, { + id: '99999999-9999-9999-9999-999999999999', + include: ['foo', 'bar'], + level: 'notify', + url: 'http://foobar.com' + }) + ) + .command(['webhooks:info', '--app', 'example-app', '99999999-9999-9999-9999-999999999999']) + .it('displays info for a given app webhook', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout).to.equal(`=== 99999999-9999-9999-9999-999999999999 +Include: foo,bar +Level: notify +URL: http://foobar.com +Webhook ID: 99999999-9999-9999-9999-999999999999 +`) + }) + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .get('/pipelines/example-pipeline/webhooks/99999999-9999-9999-9999-999999999999') + .reply(200, { + id: '99999999-9999-9999-9999-999999999999', + include: ['foo', 'bar'], + level: 'notify', + url: 'http://foobar.com' + }) + ) + .command(['webhooks:info', '--pipeline', 'example-pipeline', '99999999-9999-9999-9999-999999999999']) + .it('displays info for a given pipeline webhook', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout).to.equal(`=== 99999999-9999-9999-9999-999999999999 +Include: foo,bar +Level: notify +URL: http://foobar.com +Webhook ID: 99999999-9999-9999-9999-999999999999 +`) + }) +}) diff --git a/packages/webhooks/test/commands/webhooks/remove.test.ts b/packages/webhooks/test/commands/webhooks/remove.test.ts new file mode 100644 index 0000000000..43e75e27dd --- /dev/null +++ b/packages/webhooks/test/commands/webhooks/remove.test.ts @@ -0,0 +1,29 @@ +import {expect, test} from '@oclif/test' + +describe('webhooks:remove', () => { + test + .stderr() + .stdout() + .nock('https://api.heroku.com', api => api + .delete('/apps/example-app/webhooks/99999999-9999-9999-9999-999999999999') + .reply(200, {}) + ) + .command(['webhooks:remove', '--app', 'example-app', '99999999-9999-9999-9999-999999999999']) + .it('removes the specified app webhook', ctx => { + expect(ctx.stdout).to.equal('') + expect(ctx.stderr).to.contain('Removing webhook 99999999-9999-9999-9999-999999999999 from example-app... done\n') + }) + + test + .stderr() + .stdout() + .nock('https://api.heroku.com', api => api + .delete('/pipelines/example-pipeline/webhooks/99999999-9999-9999-9999-999999999999') + .reply(200, {}) + ) + .command(['webhooks:remove', '--pipeline', 'example-pipeline', '99999999-9999-9999-9999-999999999999']) + .it('removes the specified pipeline webhook', ctx => { + expect(ctx.stdout).to.equal('') + expect(ctx.stderr).to.contain('Removing webhook 99999999-9999-9999-9999-999999999999 from example-pipeline... done\n') + }) +}) diff --git a/packages/webhooks/test/commands/webhooks/update.test.ts b/packages/webhooks/test/commands/webhooks/update.test.ts new file mode 100644 index 0000000000..a8df30b6cc --- /dev/null +++ b/packages/webhooks/test/commands/webhooks/update.test.ts @@ -0,0 +1,55 @@ +import {expect, test} from '@oclif/test' + +describe('webhooks:update', () => { + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .patch('/apps/example-app/webhooks/99999999-9999-9999-9999-999999999999', { + include: ['foo', 'bar'], + level: 'notify', + secret: '1234', + url: 'http://foobar.com' + }) + .reply(200, {}) + ) + .command([ + 'webhooks:update', + '--app', 'example-app', + '--include', 'foo,bar', + '--secret', '1234', + '--level', 'notify', + '--url', 'http://foobar.com', + '99999999-9999-9999-9999-999999999999' + ]) + .it('updates app webhooks', ctx => { + expect(ctx.stdout).to.equal('') + expect(ctx.stderr).to.contain('Updating webhook 99999999-9999-9999-9999-999999999999 for example-app... done\n') + }) + + test + .stdout() + .stderr() + .nock('https://api.heroku.com', api => api + .patch('/pipelines/example-pipeline/webhooks/99999999-9999-9999-9999-999999999999', { + include: ['foo', 'bar'], + level: 'notify', + secret: '1234', + url: 'http://foobar.com' + }) + .reply(200, {}) + ) + .command([ + 'webhooks:update', + '--pipeline', 'example-pipeline', + '--include', 'foo,bar', + '--secret', '1234', + '--level', 'notify', + '--url', 'http://foobar.com', + '99999999-9999-9999-9999-999999999999' + ]) + .it('updates pipelines webhooks', ctx => { + expect(ctx.stdout).to.equal('') + expect(ctx.stderr).to.contain('Updating webhook 99999999-9999-9999-9999-999999999999 for example-pipeline... done\n') + }) +}) diff --git a/packages/webhooks/test/helpers/init.js b/packages/webhooks/test/helpers/init.js new file mode 100644 index 0000000000..e37b3fac3e --- /dev/null +++ b/packages/webhooks/test/helpers/init.js @@ -0,0 +1,10 @@ +// hardcodes `columns` terminal width for tests which is +// important for things like tables and other places where +// dynamic wrapping or truncating is an issue. +// see: https://github.com/oclif/screen + +global.columns = 140 + +// disable color for tests +const { color } = require('@heroku-cli/color') +color.enabled = false diff --git a/packages/webhooks/test/mocha.opts b/packages/webhooks/test/mocha.opts new file mode 100644 index 0000000000..1e74adb03d --- /dev/null +++ b/packages/webhooks/test/mocha.opts @@ -0,0 +1,6 @@ +--require test/helpers/init.js +--require ts-node/register +--watch-extensions ts +--recursive +--reporter spec +--timeout 10000 diff --git a/packages/webhooks/test/tsconfig.json b/packages/webhooks/test/tsconfig.json new file mode 100644 index 0000000000..95898fcedf --- /dev/null +++ b/packages/webhooks/test/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../tsconfig", + "compilerOptions": { + "noEmit": true + }, + "references": [ + {"path": ".."} + ] +} diff --git a/packages/webhooks/tsconfig.json b/packages/webhooks/tsconfig.json new file mode 100644 index 0000000000..f20eee7215 --- /dev/null +++ b/packages/webhooks/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "declaration": true, + "importHelpers": true, + "module": "commonjs", + "outDir": "lib", + "rootDir": "src", + "strict": true, + "target": "es2017", + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/webhooks/tslint.json b/packages/webhooks/tslint.json new file mode 100644 index 0000000000..f5703540c9 --- /dev/null +++ b/packages/webhooks/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "@oclif/tslint" +} diff --git a/yarn.lock b/yarn.lock index 815596175c..16c9c679d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2925,7 +2925,7 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -date-fns@^1.29.0: +date-fns@^1.29.0, date-fns@^1.30.1: version "1.30.1" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==