hubot 3.4.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/release.yml +36 -0
- package/.node-version +1 -0
- package/README.md +4 -1
- package/bin/hubot +1 -1
- package/docs/adapters/development.md +35 -36
- package/docs/implementation.md +1 -3
- package/docs/index.md +5 -10
- package/docs/patterns.md +132 -101
- package/docs/scripting.md +493 -411
- package/package.json +19 -18
- package/src/adapters/shell.js +4 -9
- package/src/robot.js +2 -2
- package/test/datastore_test.js +4 -0
- package/test/robot_test.js +2 -2
- package/test/shell_test.js +72 -0
- package/.env.example +0 -2
- package/.envrc +0 -5
- package/.travis.yml +0 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hubot",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"author": "hubot",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"github",
|
|
@@ -15,26 +15,23 @@
|
|
|
15
15
|
"url": "https://github.com/hubotio/hubot.git"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"async": "
|
|
19
|
-
"chalk": "^1.0.0",
|
|
18
|
+
"async": "^3.2.4",
|
|
20
19
|
"cline": "^0.8.2",
|
|
21
|
-
"coffeescript": "
|
|
22
|
-
"connect-multiparty": "^2.
|
|
23
|
-
"express": "^4.
|
|
24
|
-
"express-basic-auth": "1.1
|
|
20
|
+
"coffeescript": "^2.7.0",
|
|
21
|
+
"connect-multiparty": "^2.2.0",
|
|
22
|
+
"express": "^4.18.2",
|
|
23
|
+
"express-basic-auth": "^1.2.1",
|
|
25
24
|
"log": "1.4.0",
|
|
26
|
-
"optparse": "1.0.
|
|
25
|
+
"optparse": "^1.0.5"
|
|
27
26
|
},
|
|
28
27
|
"devDependencies": {
|
|
29
|
-
"chai": "
|
|
30
|
-
"coveralls": "^3.0.2",
|
|
28
|
+
"chai": "^4.3.7",
|
|
31
29
|
"is-circular": "^1.0.2",
|
|
32
30
|
"mocha": "^10.2.0",
|
|
33
|
-
"mockery": "^1.
|
|
34
|
-
"nyc": "^15.1.0",
|
|
31
|
+
"mockery": "^2.1.0",
|
|
35
32
|
"semantic-release": "^21.0.1",
|
|
36
|
-
"sinon": "
|
|
37
|
-
"sinon-chai": "^
|
|
33
|
+
"sinon": "^15.0.4",
|
|
34
|
+
"sinon-chai": "^3.7.0",
|
|
38
35
|
"standard": "^17.0.0"
|
|
39
36
|
},
|
|
40
37
|
"engines": {
|
|
@@ -48,9 +45,13 @@
|
|
|
48
45
|
"scripts": {
|
|
49
46
|
"start": "bin/hubot",
|
|
50
47
|
"pretest": "standard",
|
|
51
|
-
"test": "
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
"test": "mocha --exit",
|
|
49
|
+
"test:smoke": "node src/**/*.js"
|
|
50
|
+
},
|
|
51
|
+
"release": {
|
|
52
|
+
"branches": [
|
|
53
|
+
"master"
|
|
54
|
+
],
|
|
55
|
+
"dryRun": false
|
|
55
56
|
}
|
|
56
57
|
}
|
package/src/adapters/shell.js
CHANGED
|
@@ -4,7 +4,6 @@ const fs = require('fs')
|
|
|
4
4
|
const readline = require('readline')
|
|
5
5
|
const Stream = require('stream')
|
|
6
6
|
const cline = require('cline')
|
|
7
|
-
const chalk = require('chalk')
|
|
8
7
|
|
|
9
8
|
const Adapter = require('../adapter')
|
|
10
9
|
|
|
@@ -15,12 +14,13 @@ const TextMessage = _require.TextMessage
|
|
|
15
14
|
const historySize = process.env.HUBOT_SHELL_HISTSIZE != null ? parseInt(process.env.HUBOT_SHELL_HISTSIZE) : 1024
|
|
16
15
|
|
|
17
16
|
const historyPath = '.hubot_history'
|
|
17
|
+
const bold = str => `\x1b[1m${str}\x1b[22m`
|
|
18
18
|
|
|
19
19
|
class Shell extends Adapter {
|
|
20
20
|
send (envelope/* , ...strings */) {
|
|
21
21
|
const strings = [].slice.call(arguments, 1)
|
|
22
22
|
|
|
23
|
-
Array.from(strings).forEach(str => console.log(
|
|
23
|
+
Array.from(strings).forEach(str => console.log(bold(str)))
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
emote (envelope/* , ...strings */) {
|
|
@@ -36,15 +36,13 @@ class Shell extends Adapter {
|
|
|
36
36
|
|
|
37
37
|
run () {
|
|
38
38
|
this.buildCli()
|
|
39
|
-
|
|
40
39
|
loadHistory((error, history) => {
|
|
41
40
|
if (error) {
|
|
42
41
|
console.log(error.message)
|
|
43
42
|
}
|
|
44
|
-
|
|
45
43
|
this.cli.history(history)
|
|
46
44
|
this.cli.interact(`${this.robot.name}> `)
|
|
47
|
-
return this.emit('connected')
|
|
45
|
+
return this.emit('connected', this)
|
|
48
46
|
})
|
|
49
47
|
}
|
|
50
48
|
|
|
@@ -97,14 +95,11 @@ class Shell extends Adapter {
|
|
|
97
95
|
}
|
|
98
96
|
|
|
99
97
|
const outstream = fs.createWriteStream(historyPath, fileOpts)
|
|
100
|
-
outstream.on('
|
|
101
|
-
|
|
98
|
+
outstream.on('end', this.shutdown.bind(this))
|
|
102
99
|
for (i = 0, len = history.length; i < len; i++) {
|
|
103
100
|
item = history[i]
|
|
104
101
|
outstream.write(item + '\n')
|
|
105
102
|
}
|
|
106
|
-
|
|
107
|
-
outstream.end(this.shutdown.bind(this))
|
|
108
103
|
})
|
|
109
104
|
}
|
|
110
105
|
}
|
package/src/robot.js
CHANGED
|
@@ -317,13 +317,13 @@ class Robot {
|
|
|
317
317
|
// stack doesn't get too big
|
|
318
318
|
process.nextTick(() =>
|
|
319
319
|
// Stop processing when message.done == true
|
|
320
|
-
done(context.response.message.done)
|
|
320
|
+
done(null, context.response.message.done)
|
|
321
321
|
)
|
|
322
322
|
})
|
|
323
323
|
} catch (err) {
|
|
324
324
|
this.emit('error', err, new this.Response(this, context.response.message, []))
|
|
325
325
|
// Continue to next listener when there is an error
|
|
326
|
-
done(false)
|
|
326
|
+
done(null, false)
|
|
327
327
|
}
|
|
328
328
|
},
|
|
329
329
|
// Ignore the result ( == the listener that set message.done = true)
|
package/test/datastore_test.js
CHANGED
|
@@ -30,6 +30,10 @@ describe('Datastore', function () {
|
|
|
30
30
|
this.robot.brain.userForId('2', { name: 'User Two' })
|
|
31
31
|
})
|
|
32
32
|
|
|
33
|
+
this.afterEach(function () {
|
|
34
|
+
this.clock.restore()
|
|
35
|
+
})
|
|
36
|
+
|
|
33
37
|
describe('global scope', function () {
|
|
34
38
|
it('returns undefined for values not in the datastore', function () {
|
|
35
39
|
return this.robot.datastore.get('blah').then(function (value) {
|
package/test/robot_test.js
CHANGED
|
@@ -374,7 +374,7 @@ describe('Robot', function () {
|
|
|
374
374
|
|
|
375
375
|
describe('#loadFile', function () {
|
|
376
376
|
beforeEach(function () {
|
|
377
|
-
this.sandbox = sinon.
|
|
377
|
+
this.sandbox = sinon.createSandbox()
|
|
378
378
|
})
|
|
379
379
|
|
|
380
380
|
afterEach(function () {
|
|
@@ -724,7 +724,7 @@ describe('Robot', function () {
|
|
|
724
724
|
this.robot.catchAll(catchAllCallback)
|
|
725
725
|
|
|
726
726
|
this.robot.receive(testMessage, function () {
|
|
727
|
-
expect(listenerCallback).to.have.been.
|
|
727
|
+
expect(listenerCallback).to.have.been.calledOnce
|
|
728
728
|
expect(catchAllCallback).to.not.have.been.called
|
|
729
729
|
done()
|
|
730
730
|
})
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/* global describe, beforeEach, it */
|
|
4
|
+
|
|
5
|
+
const chai = require('chai')
|
|
6
|
+
const sinon = require('sinon')
|
|
7
|
+
chai.use(require('sinon-chai'))
|
|
8
|
+
|
|
9
|
+
const expect = chai.expect
|
|
10
|
+
|
|
11
|
+
const Robot = require('../src/robot')
|
|
12
|
+
|
|
13
|
+
describe('Shell Adapter', function () {
|
|
14
|
+
beforeEach(function () {
|
|
15
|
+
this.robot = new Robot(null, 'shell', false, 'TestHubot')
|
|
16
|
+
this.robot.run()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
this.afterEach(function () {
|
|
20
|
+
this.robot.shutdown()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
describe('Public API', function () {
|
|
24
|
+
beforeEach(function () {
|
|
25
|
+
this.adapter = this.robot.adapter
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('assigns robot', function () {
|
|
29
|
+
expect(this.adapter.robot).to.equal(this.robot)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('sends a message', function () {
|
|
33
|
+
this.adapter.send = sinon.spy()
|
|
34
|
+
this.adapter.send({ room: 'general' }, 'hello')
|
|
35
|
+
|
|
36
|
+
expect(this.adapter.send).to.have.been.calledWith({ room: 'general' }, 'hello')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('emotes a message', function () {
|
|
40
|
+
this.adapter.send = sinon.spy()
|
|
41
|
+
this.adapter.emote({ room: 'general' }, 'hello')
|
|
42
|
+
|
|
43
|
+
expect(this.adapter.send).to.have.been.calledWith({ room: 'general' }, '* hello')
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('replies to a message', function () {
|
|
47
|
+
this.adapter.send = sinon.spy()
|
|
48
|
+
this.adapter.reply({ room: 'general', user: { name: 'mocha' } }, 'hello')
|
|
49
|
+
|
|
50
|
+
expect(this.adapter.send).to.have.been.calledWith({ room: 'general', user: { name: 'mocha' } }, 'mocha: hello')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('runs the adapter and emits connected', function (done) {
|
|
54
|
+
const connected = () => {
|
|
55
|
+
this.adapter.off('connected', connected)
|
|
56
|
+
done()
|
|
57
|
+
}
|
|
58
|
+
this.adapter.on('connected', connected)
|
|
59
|
+
this.adapter.run()
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('dispatches received messages to the robot', function () {
|
|
64
|
+
this.robot.receive = sinon.spy()
|
|
65
|
+
this.adapter = this.robot.adapter
|
|
66
|
+
this.message = sinon.spy()
|
|
67
|
+
|
|
68
|
+
this.adapter.receive(this.message)
|
|
69
|
+
|
|
70
|
+
expect(this.robot.receive).to.have.been.calledWith(this.message)
|
|
71
|
+
})
|
|
72
|
+
})
|
package/.env.example
DELETED
package/.envrc
DELETED
package/.travis.yml
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
language: node_js
|
|
2
|
-
node_js:
|
|
3
|
-
- "10"
|
|
4
|
-
- "8"
|
|
5
|
-
- "6"
|
|
6
|
-
notifications:
|
|
7
|
-
email: false
|
|
8
|
-
sudo: false
|
|
9
|
-
addons:
|
|
10
|
-
apt:
|
|
11
|
-
packages:
|
|
12
|
-
- expect
|
|
13
|
-
before_install:
|
|
14
|
-
- npm install -g npm@latest
|
|
15
|
-
before_script:
|
|
16
|
-
- npm prune
|
|
17
|
-
- bin/e2e-test.sh
|
|
18
|
-
after_success:
|
|
19
|
-
- npm run coverage
|
|
20
|
-
branches:
|
|
21
|
-
except:
|
|
22
|
-
- /^v\d+\.\d+\.\d+$/
|
|
23
|
-
deploy:
|
|
24
|
-
provider: script
|
|
25
|
-
skip_cleanup: true
|
|
26
|
-
script:
|
|
27
|
-
- npx travis-deploy-once "npx semantic-release"
|