diff --git a/README.md b/README.md index 0b2e6567c..0eb7d5d30 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ # Hubot +**Please note that in v11, CoffeeScript support was removed.** + Hubot is a framework to build chat bots, modeled after GitHub's Campfire bot of the same name, hubot. He's pretty cool. He's [extendable with scripts](https://hubotio.github.io/hubot/docs#scripts) and can work on [many different chat services](https://hubotio.github.io/hubot/adapters.html). diff --git a/bin/e2e-test.sh b/bin/e2e-test.sh index 36d7d2899..dd3b4733e 100755 --- a/bin/e2e-test.sh +++ b/bin/e2e-test.sh @@ -12,7 +12,7 @@ trap "{ CODE=$?; popd; rm -rf $TEMP_ROOT; exit $CODE; }" EXIT echo "$ create hubot in $TEMP_ROOT" echo "$ install Hubot from $HUBOT_FOLDER" npm init -y -npm i $HUBOT_FOLDER coffeescript +npm i $HUBOT_FOLDER ./node_modules/.bin/hubot --create myhubot cd myhubot diff --git a/bin/hubot b/bin/hubot index 0467bb84d..e7e2ac8bf 100755 --- a/bin/hubot +++ b/bin/hubot @@ -1,9 +1,3 @@ -#!/usr/bin/env coffee +#!/usr/bin/env node -# While all other files have been converted to JavaScript via https://github.com/github/hubot/pull/1347, -# we left the `bin/hubot` file to remain in CoffeeScript in order prevent -# breaking existing 3rd party adapters of which some are still written in -# CoffeeScript themselves. We will deprecate and eventually remove this file -# in a future version of hubot - -require './hubot.js' +require('./hubot.js') \ No newline at end of file diff --git a/docs/adapters/development.md b/docs/adapters/development.md index 12c427fe9..2261e5f9c 100644 --- a/docs/adapters/development.md +++ b/docs/adapters/development.md @@ -10,10 +10,8 @@ permalink: /adapters/development.html All adapters inherit from the Adapter class in the `src/adapter.js` file. -If you're writing your adapter in ES2015, you must require the ES2015 entrypoint instead: - ```javascript -const Adapter = require('hubot/es2015').Adapter; +const Adapter = require('hubot/index.js').Adapter; ``` There are certain methods that you will want to override. Here is a basic stub of what an extended Adapter class would look like: @@ -60,10 +58,7 @@ exports.use = (robot) => new Sample(robot) "dependencies": { }, "peerDependencies": { - "hubot": ">=3.0" - }, - "devDependencies": { - "coffeescript": ">=1.2.0" + "hubot": ">= 11" } ``` @@ -117,10 +112,7 @@ Another option is to load the file from local disk. "dependencies": { }, "peerDependencies": { - "hubot": ">=9" - }, - "devDependencies": { - "coffeescript": ">=2.7.0" + "hubot": ">= 11" } ``` diff --git a/docs/deploying/azure.md b/docs/deploying/azure.md index 15f0efdde..33c5c7a16 100644 --- a/docs/deploying/azure.md +++ b/docs/deploying/azure.md @@ -37,13 +37,12 @@ First, run the follow command to add `deploy.cmd` to your hubot directory. This Then, edit this file and look for the sections that give you steps 1, 2 and 3. You're going to add a 4th step: - :: 4. Create Hubot file with a coffee extension - copy /Y "%DEPLOYMENT_TARGET%\node_modules\hubot\bin\hubot" "%DEPLOYMENT_TARGET%\node_modules\hubot\bin\hubot.coffee" + :: 4. Create Hubot file with a js extension + copy /Y "%DEPLOYMENT_TARGET%\node_modules\hubot\bin\hubot" "%DEPLOYMENT_TARGET%\node_modules\hubot\bin\hubot.js" Now, create a new file in the base directory of hubot called `server.js` and put these two lines into it: - require('coffeescript/register'); - module.exports = require('hubot/bin/hubot.coffee'); + module.exports = require('hubot/bin/hubot.js'); Finally you will need to add the environment variables to the website to make sure it runs properly. You can either do it through the GUI (under configuration) or you can use the Azure PowerShell command line, as follows (example is showing slack as an adapter and mynewhubot as the website name). diff --git a/docs/scripting.md b/docs/scripting.md index c9a7ed3de..5218e2e2a 100644 --- a/docs/scripting.md +++ b/docs/scripting.md @@ -839,7 +839,7 @@ Listener middleware inserts logic between the listener matching a message and th ## Listener Middleware Examples -A fully functioning example can be found in [hubot-rate-limit](https://github.com/michaelansel/hubot-rate-limit/blob/master/src/rate-limit.coffee) (Note, this is a coffee version, non-async/await). +A fully functioning example can be found in [hubot-rate-limit](https://github.com/michaelansel/hubot-rate-limit/blob/master/src/rate-limit.coffee) (Note: this is a coffee version, non-async/await, and will not work with the latest Hubot since CoffeeScript support was removed in version 11). A simple example of middleware logging command executions: @@ -1005,51 +1005,55 @@ You may also want to install: [Note: This section is still refering to Coffeescript, but we've update Hubot for Javascript. We'll have to replace this when we get a JavaScript example.] -Here is a sample script that tests the first couple of commands in the [Hubot sample script](https://github.com/hubotio/generator-hubot/blob/master/generators/app/templates/scripts/example.coffee). This script uses *Mocha*, *chai*, *coffeescript*, and of course *hubot-test-helper*: +Here is a sample script that tests the first couple of commands. -**test/example-test.coffee** +**test/example-test.mjs** -```coffeescript -Helper = require('hubot-test-helper') -chai = require 'chai' - -expect = chai.expect - -helper = new Helper('../scripts/example.coffee') - -describe 'example script', -> - beforeEach -> - @room = helper.createRoom() +```javascript +import { describe, it } from 'node:test' +import assert from 'node:assert/strict' +import Helper from 'hubot-test-helper' - afterEach -> - @room.destroy() +const helper = new Helper('../scripts/example.mjs') - it 'doesn\'t need badgers', -> - @room.user.say('alice', 'did someone call for a badger?').then => - expect(@room.messages).to.eql [ - ['alice', 'did someone call for a badger?'] - ['hubot', 'Badgers? BADGERS? WE DON\'T NEED NO STINKIN BADGERS'] - ] +describe('example script', () => { + let room = null + beforeEach(() => { + room = helper.createRoom() + }) - it 'won\'t open the pod bay doors', -> - @room.user.say('bob', '@hubot open the pod bay doors').then => - expect(@room.messages).to.eql [ - ['bob', '@hubot open the pod bay doors'] - ['hubot', '@bob I\'m afraid I can\'t let you do that.'] - ] + afterEach(() => + room.destroy() + )) - it 'will open the dutch doors', -> - @room.user.say('bob', '@hubot open the dutch doors').then => - expect(@room.messages).to.eql [ - ['bob', '@hubot open the dutch doors'] - ['hubot', '@bob Opening dutch doors'] - ] + it("doesn't need badgers", async () => { + await room.user.say('alice', 'did someone call for a badger?') + assert.deepEqual(room.messages, [ + ['alice', 'did someone call for a badger?'] + ['hubot', 'Badgers? BADGERS? WE DON\'T NEED NO STINKIN BADGERS'] + ]) + }) + it("won't open the pod bay doors"), async () => { + await room.user.say('bob', '@hubot open the pod bay doors') + assert.deepEqual(room.messages, [ + ['bob', '@hubot open the pod bay doors'] + ['hubot', '@bob I\'m afraid I can\'t let you do that.'] + ]) + }) + it('will open the dutch doors'), async () => { + await room.user.say('bob', '@hubot open the dutch doors') + assert.deepEqual(room.messages, [ + ['bob', '@hubot open the dutch doors'] + ['hubot', '@bob Opening dutch doors'] + ]) + }) +} ``` **sample output** ```sh -% mocha --require coffeescript/register test/*.coffee +% node --test test/*.mjs example script ✓ doesn't need badgers ✓ won't open the pod bay doors diff --git a/es2015.js b/es2015.js deleted file mode 100644 index 0c6f377ce..000000000 --- a/es2015.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict' - -const User = require('./src/user') -const Brain = require('./src/brain') -const Robot = require('./src/robot') -const Adapter = require('./src/adapter') -const Response = require('./src/response') -const Listener = require('./src/listener') -const Message = require('./src/message') -const DataStore = require('./src/datastore') - -module.exports = { - User, - Brain, - Robot, - Adapter, - Response, - Listener: Listener.Listener, - TextListener: Listener.TextListener, - Message: Message.Message, - TextMessage: Message.TextMessage, - EnterMessage: Message.EnterMessage, - LeaveMessage: Message.LeaveMessage, - TopicMessage: Message.TopicMessage, - CatchAllMessage: Message.CatchAllMessage, - DataStore: DataStore.DataStore, - DataStoreUnavailable: DataStore.DataStoreUnavailable, - loadBot (adapter, enableHttpd, name, alias) { - return new module.exports.Robot(adapter, enableHttpd, name, alias) - } -} diff --git a/index.js b/index.js index 5c742efd4..0c6f377ce 100644 --- a/index.js +++ b/index.js @@ -1,40 +1,31 @@ 'use strict' -require('coffeescript/register') -const inherits = require('util').inherits - -const hubotExport = require('./es2015') - -// make all es2015 class declarations compatible with CoffeeScript’s extend -// see https://github.com/hubotio/evolution/pull/4#issuecomment-306437501 -module.exports = Object.keys(hubotExport).reduce((map, current) => { - if (current !== 'loadBot') { - map[current] = makeClassCoffeeScriptCompatible(hubotExport[current]) - } else { - map[current] = hubotExport[current] - } - return map -}, {}) - -function makeClassCoffeeScriptCompatible (klass) { - function CoffeeScriptCompatibleClass () { - const Hack = Function.prototype.bind.apply(klass, [null].concat([].slice.call(arguments))) - const instance = new Hack() - - // pass methods from child to returned instance - for (const key in this) { - instance[key] = this[key] - } - - // support for constructor methods which call super() - // in which this.* properties are set - for (const key in instance) { - this[key] = instance[key] - } - - return instance +const User = require('./src/user') +const Brain = require('./src/brain') +const Robot = require('./src/robot') +const Adapter = require('./src/adapter') +const Response = require('./src/response') +const Listener = require('./src/listener') +const Message = require('./src/message') +const DataStore = require('./src/datastore') + +module.exports = { + User, + Brain, + Robot, + Adapter, + Response, + Listener: Listener.Listener, + TextListener: Listener.TextListener, + Message: Message.Message, + TextMessage: Message.TextMessage, + EnterMessage: Message.EnterMessage, + LeaveMessage: Message.LeaveMessage, + TopicMessage: Message.TopicMessage, + CatchAllMessage: Message.CatchAllMessage, + DataStore: DataStore.DataStore, + DataStoreUnavailable: DataStore.DataStoreUnavailable, + loadBot (adapter, enableHttpd, name, alias) { + return new module.exports.Robot(adapter, enableHttpd, name, alias) } - inherits(CoffeeScriptCompatibleClass, klass) - - return CoffeeScriptCompatibleClass } diff --git a/package-lock.json b/package-lock.json index e5553c666..a6156e3eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "9.1.0", "license": "MIT", "dependencies": { - "coffeescript": "^2.7.0", "connect-multiparty": "^2.2.0", "express": "^4.18.2", "express-basic-auth": "^1.2.1", @@ -670,18 +669,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/coffeescript": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.7.0.tgz", - "integrity": "sha512-hzWp6TUE2d/jCcN67LrW1eh5b/rSDKQK6oD6VMLlggYVUUFexgTH9z3dNYihzX4RMhze5FTUsUmOXViJKFQR/A==", - "bin": { - "cake": "bin/cake", - "coffee": "bin/coffee" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", diff --git a/package.json b/package.json index 3d49cf43c..2de0daf95 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "url": "https://github.com/hubotio/hubot.git" }, "dependencies": { - "coffeescript": "^2.7.0", "connect-multiparty": "^2.2.0", "express": "^4.18.2", "express-basic-auth": "^1.2.1", diff --git a/src/robot.js b/src/robot.js index 1882d1d06..9df585748 100644 --- a/src/robot.js +++ b/src/robot.js @@ -328,10 +328,6 @@ class Robot { } } - async loadcoffee (filePath) { - return await this.loadjs(filePath) - } - async loadjs (filePath) { const script = require(filePath) if (typeof script === 'function') { @@ -352,7 +348,7 @@ class Robot { const full = path.join(filepath, path.basename(filename)) // see https://github.com/hubotio/hubot/issues/1355 - if (['js', 'mjs', 'coffee'].indexOf(ext) === -1) { + if (['js', 'mjs'].indexOf(ext) === -1) { this.logger.debug(`Skipping unsupported file type ${full}`) return } @@ -480,7 +476,7 @@ class Robot { try { if (Array.from(HUBOT_DEFAULT_ADAPTERS).indexOf(this.adapterName) > -1) { this.adapter = this.requireAdapterFrom(path.resolve(path.join(__dirname, 'adapters', this.adapterName))) - } else if (['.js', '.cjs', '.coffee'].includes(ext)) { + } else if (['.js', '.cjs'].includes(ext)) { this.adapter = this.requireAdapterFrom(path.resolve(adapterPath)) } else if (['.mjs'].includes(ext)) { this.adapter = await this.importAdapterFrom(pathToFileURL(path.resolve(adapterPath)).href) diff --git a/test/fixtures/MockAdapter.mjs b/test/fixtures/MockAdapter.mjs index 5366ba072..5ebb9f4f9 100644 --- a/test/fixtures/MockAdapter.mjs +++ b/test/fixtures/MockAdapter.mjs @@ -1,6 +1,6 @@ 'use strict' -import { Adapter } from '../../es2015.js' // eslint-disable-line import/no-unresolved +import { Adapter } from '../../index.js' class MockAdapter extends Adapter { constructor (robot) { diff --git a/test/fixtures/TestScript.coffee b/test/fixtures/TestScript.coffee deleted file mode 100644 index 8aeaba1ce..000000000 --- a/test/fixtures/TestScript.coffee +++ /dev/null @@ -1,9 +0,0 @@ -# Description: A test script for the robot to load -# -# Commands: -# hubot test - Responds with a test response -# - -module.exports = (robot) -> - robot.respond 'test', (res) -> - res.send 'test response from coffeescript' diff --git a/test/es2015_test.js b/test/index_test.js similarity index 98% rename from test/es2015_test.js rename to test/index_test.js index a87ec62e6..ac66b8061 100644 --- a/test/es2015_test.js +++ b/test/index_test.js @@ -8,7 +8,7 @@ const assert = require('assert/strict') const { hook, reset } = require('./fixtures/RequireMocker.js') // Hubot classes -const Hubot = require('../es2015.js') +const Hubot = require('../index.js') const User = Hubot.User const Brain = Hubot.Brain const Robot = Hubot.Robot @@ -23,7 +23,7 @@ const LeaveMessage = Hubot.LeaveMessage const TopicMessage = Hubot.TopicMessage const CatchAllMessage = Hubot.CatchAllMessage -describe('hubot/es2015', () => { +describe('hubot/index', () => { it('exports User class', () => { class MyUser extends User {} const user = new MyUser('id123', { foo: 'bar' }) diff --git a/test/robot_test.js b/test/robot_test.js index 0f2889783..df73e5677 100644 --- a/test/robot_test.js +++ b/test/robot_test.js @@ -1,7 +1,7 @@ 'use strict' /* eslint-disable no-unused-expressions */ -require('coffeescript/register.js') + const { describe, it, beforeEach, afterEach } = require('node:test') const assert = require('assert/strict') @@ -966,29 +966,6 @@ describe('Robot', () => { await robot.receive(new TextMessage('tester', 'hubot test')) }) }) - describe('Robot Coffeescript', () => { - let robot = null - beforeEach(async () => { - robot = new Robot('MockAdapter', false, 'TestHubot') - robot.alias = 'Hubot' - await robot.loadAdapter('./test/fixtures/MockAdapter.coffee') - await robot.loadFile(path.resolve('./test/fixtures/'), 'TestScript.coffee') - await robot.run() - }) - afterEach(() => { - robot.shutdown() - }) - it('should load a CoffeeScript adapter from a file', async () => { - assert.equal(robot.adapter.name, 'MockAdapter') - }) - it('should load a coffeescript file and respond to a message', async () => { - const sent = async (envelop, strings) => { - assert.deepEqual(strings, ['test response from coffeescript']) - } - robot.adapter.on('send', sent) - await robot.receive(new TextMessage('tester', 'hubot test')) - }) - }) describe('Robot Defaults', () => { let robot = null beforeEach(async () => {