rodbot 0.3.1 → 0.3.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f32541e2113ba1425a81da6374fc3353d578ba5fd0b9b1905f5eeae95fab0180
4
- data.tar.gz: ad474b634ffa0fb96fe23cb7602b9de81df2367636cb0327cce578901237615d
3
+ metadata.gz: 6e6caa3fc8d7a38fb433cc01dedd9e521f2a7c2cd79ebaa4f78396c39f1a5cfc
4
+ data.tar.gz: 8d7f438f66d0d8494c7629ea3f1f363f730ce34a0c5178aaca0ee580e6a7a512
5
5
  SHA512:
6
- metadata.gz: 45fc1790e2d559610ebca8ce834bcaf245f6fb922e18edd56d55f2ee307fbf2daffe2db10b507efc1944d27e4c562577108013c48186e6a743bf2e5cd1dfe67b
7
- data.tar.gz: 9787f11da1619228e571644be1643e66d3b4b65f46ed14d2782b9b20a73b35f98f33bce02bd26c5dd7677e377e09874945412155cca9e55e220363cd41776e4a
6
+ metadata.gz: 7ddbdf27810f750712ff0a7990ec6da94d084a289c9364d380ae33d1107dd6693ce60b099ea0826aba551a61fc3033b2ea6c6808ef67aa367eac29802cae5e30
7
+ data.tar.gz: 5160f0113df885f7ec1597b18eaee70420d82eb0cc11b66d54ee7bb5642f7e95224b1a33c97ced6d75bd89ad6b061627e4a518811a828bbc10c6d66cfbcb4194
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  Nothing so far
4
4
 
5
+ ## 0.3.3
6
+
7
+ #### Additions
8
+ * Support placeholders when using `Rodbot.say` and add `[[EVERYBODY]]`
9
+ placeholder to mention all hands in a room or channel.
10
+
11
+ ## 0.3.2
12
+
13
+ #### Additions
14
+ * Simple /healthz route e.g. for deployments on render.com
15
+ * Deploy templates for render.com
16
+
17
+ #### Changes
18
+ * Switch from httparty to httpx
19
+
5
20
  ## 0.3.1
6
21
 
7
22
  #### Fixes
data/README.md CHANGED
@@ -166,6 +166,7 @@ The response may contain special tags which have to be replace appropriately by
166
166
  Tag | Replaced with
167
167
  ----|--------------
168
168
  `[[SENDER]]` | Mention the sender of the command.
169
+ `[[EVERYBODY]]` | Mention everybody.
169
170
 
170
171
  #### Other Routes
171
172
 
@@ -302,13 +303,13 @@ overmind start
302
303
 
303
304
  ## Request
304
305
 
305
- To query the **app service**, you can either use the bundled [HTTParty](https://rubygems.org/gems/httparty) gem or the following convenience wrapper:
306
+ To query the **app service**, you can either use the bundled [HTTPX](https://rubygems.org/gems/httpx) gem or the following convenience wrapper:
306
307
 
307
308
  ```ruby
308
- response = Rodbot.request('/time', query: { zone: 'UTC' })
309
+ response = Rodbot.request('/time', params: { zone: 'UTC' })
309
310
  ```
310
311
 
311
- This uses the default `method: :get` and the default `timeout: 10` seconds, it returns an instance of [HTTParty::Response](https://www.rubydoc.info/gems/httparty/HTTParty/Response):
312
+ This uses the default `method: :get` and the default `timeout: 10` seconds, it returns an instance of [HTTPX::Response](https://www.rubydoc.info/gems/httpx/HTTPX/Response):
312
313
 
313
314
  ```ruby
314
315
  response.code # => 200
@@ -0,0 +1 @@
1
+ 3704bffdb0e27a9544bbdc7538051a9253eeefe81bbbfeea14e1f486e36c701ae200a1b6da151306a96d8e8ccb154236cf18ce4cb27821cd42cbc165a6bc79e6
@@ -0,0 +1 @@
1
+ de9183abfb13dd5098ca5e8e2cba6b0e27f349c2e90b85ef387e5b81730ff7d911f29b47b7e4900719e198514d097513f109916c6e64f2b9361237b35b5b0a70
@@ -22,7 +22,7 @@ module Rodbot
22
22
  class Generator
23
23
 
24
24
  # Glob to filter relevant template files
25
- GLOB = "**/{*,.ruby-version,.gitignore,.keep}"
25
+ GLOB = "**/{*,.ruby-version*,.gitignore,.keep}"
26
26
 
27
27
  # Colors used by +info+ to color part of the output
28
28
  TAG_COLORS = {
@@ -38,8 +38,9 @@ module Rodbot
38
38
 
39
39
  # Print the interpolated template to STDOUT
40
40
  def display
41
+ puts
41
42
  each_template_path do |template_path, target_path, content|
42
- puts "# #{target_path}", (content || template_path.read)
43
+ puts "### #{target_path} ###", (content || template_path.read), nil
43
44
  end
44
45
  end
45
46
 
@@ -57,10 +57,10 @@ module Rodbot
57
57
  server = TCPServer.new(*bind)
58
58
  loop do
59
59
  Thread.start(server.accept) do |remote|
60
- body = remote.gets("\x04")
60
+ md = remote.gets("\x04").chop
61
61
  remote.close
62
- body.force_encoding('UTF-8')
63
- room.send_html body.md_to_html
62
+ md.force_encoding('UTF-8')
63
+ room.send_html md.psub(placeholders).md_to_html
64
64
  end
65
65
  end
66
66
  end
@@ -71,21 +71,20 @@ module Rodbot
71
71
 
72
72
  def on_message(message)
73
73
  if message.content[:msgtype] == 'm.text' && message.content[:body].start_with?('!')
74
- html = 'pong' if message.content[:body] == '!ping'
75
- html ||= reply_to(message)
76
- room.send_html(html)
74
+ room.send_html(reply_to(message))
77
75
  end
78
76
  end
79
77
 
80
78
  def reply_to(message)
81
79
  command(*message.content[:body][1..].split(/\s+/, 2)).
82
80
  md_to_html.
83
- psub(placeholders(client.get_user(message.sender)))
81
+ psub(placeholders(sender: client.get_user(message.sender)))
84
82
  end
85
83
 
86
- def placeholders(sender)
84
+ def placeholders(locals={})
87
85
  {
88
- sender: "https://matrix.to/#/#{sender.id}"
86
+ sender: ("https://matrix.to/#/#{locals[:sender].id}" if locals[:sender]),
87
+ everybody: "https://matrix.to/#room"
89
88
  }
90
89
  end
91
90
 
@@ -39,10 +39,14 @@ module Rodbot
39
39
  server = TCPServer.new(*bind)
40
40
  loop do
41
41
  Thread.start(server.accept) do |remote|
42
- body = remote.gets("\x04")
42
+ md = remote.gets("\x04").chop
43
43
  remote.close
44
- body.force_encoding('UTF-8')
45
- client.web_client.chat_postMessage(channel: channel_id, text: body, as_user: true)
44
+ md.force_encoding('UTF-8')
45
+ client.web_client.chat_postMessage(
46
+ channel: channel_id,
47
+ text: md_to_slack_text(md.psub(placeholders)),
48
+ as_user: true
49
+ )
46
50
  end
47
51
  end
48
52
  end
@@ -56,23 +60,35 @@ module Rodbot
56
60
 
57
61
  def on_message(message)
58
62
  if message.text.start_with?('!')
59
- md = 'pong' if message.text == '!ping'
60
- md ||= reply_to(message)
61
- client.web_client.chat_postMessage(channel: message.channel, text: md, as_user: true)
63
+ client.web_client.chat_postMessage(
64
+ channel: message.channel,
65
+ text: reply_to(message),
66
+ as_user: true
67
+ )
62
68
  end
63
69
  end
64
70
 
65
71
  def reply_to(message)
66
72
  command(*message.text[1..].split(/\s+/, 2)).
67
- psub(placeholders(message.user))
73
+ psub(placeholders(sender: message.user)).
74
+ then { md_to_slack_text(_1) }
68
75
  end
69
76
 
70
- def placeholders(sender)
77
+ # @see https://api.slack.com/reference/surfaces/formatting
78
+ def placeholders(locals={})
71
79
  {
72
- sender: "<@#{sender}>"
80
+ sender: ("<@#{locals[:sender]}>" if locals[:sender]),
81
+ everybody: "<!channel>"
73
82
  }
74
83
  end
75
84
 
85
+ # @see https://api.slack.com/reference/surfaces/formatting
86
+ def md_to_slack_text(md)
87
+ md.
88
+ gsub(/\[(.+?)\]\((.+?)\)/, '<\2|\1>'). # convert links
89
+ gsub(/^\s*[*-]\s+/, '• ') # convert bullet lists
90
+ end
91
+
76
92
  end
77
93
  end
78
94
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'httparty'
3
+ require 'httpx'
4
4
 
5
5
  module Rodbot
6
6
  class Plugins
@@ -24,11 +24,11 @@ module Rodbot
24
24
 
25
25
  class Today
26
26
  def initialize
27
- @response = HTTParty.get('https://www.merriam-webster.com/word-of-the-day')
27
+ @response = HTTPX.with(timeout: { request_timeout: 60 }).get('https://www.merriam-webster.com/word-of-the-day')
28
28
  end
29
29
 
30
30
  def message
31
- if @response.success?
31
+ if @response.status == 200
32
32
  "Word of the day: [#{word}](#{url})"
33
33
  else
34
34
  "Sorry, there was a problem fetching the word of the day."
@@ -38,11 +38,11 @@ module Rodbot
38
38
  private
39
39
 
40
40
  def word
41
- @response.body.match(/<h2 class="word-header-txt">(.+?)</).captures.first
41
+ @response.body.to_s.match(/<h2 class="word-header-txt">(.+?)</).captures.first
42
42
  end
43
43
 
44
44
  def url
45
- @response.body.match(/<meta property="og:url" content="(.+?)"/).captures.first
45
+ @response.body.to_s.match(/<meta property="og:url" content="(.+?)"/).captures.first
46
46
  end
47
47
  end
48
48
 
data/lib/rodbot/rack.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen-string-literal: true
2
2
 
3
- require 'httparty'
3
+ require 'httpx'
4
4
 
5
5
  using Rodbot::Refinements
6
6
 
@@ -36,12 +36,11 @@ module Rodbot
36
36
  # Send request to the app service
37
37
  #
38
38
  # @param path [String] path e.g. +/help+
39
- # @param query [Hash] query hash e.g. +{ search: 'foobar' }+
40
- # @param method [Symbol, String] HTTP method
39
+ # @param params [Hash] params hash e.g. +{ search: 'foobar' }+
41
40
  # @param timeout [Integer] max seconds to wait for response
42
- # @return [HTTParty::Response]
43
- def request(path, query: {}, method: :get, timeout: 10)
44
- HTTParty.send(method, Rodbot::Services::App.url.uri_concat(path), query: query, timeout: timeout)
41
+ # @return [HTTPX::Response]
42
+ def request(path, params: {}, timeout: 10)
43
+ HTTPX.with(timeout: { request_timeout: timeout }).get(Rodbot::Services::App.url.uri_concat(path), params: params)
45
44
  end
46
45
 
47
46
  end
data/lib/rodbot/relay.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'digest'
4
4
  require 'socket'
5
- require 'httparty'
5
+ require 'httpx'
6
6
 
7
7
  module Rodbot
8
8
 
@@ -84,15 +84,28 @@ module Rodbot
84
84
  ]
85
85
  end
86
86
 
87
- # Perform the command on the app using a GET request
87
+ # Perform the built-in command or fall back to the app using +request+
88
88
  #
89
89
  # @param command [String] command to perform
90
90
  # @param argument [String, nil] optional arguments
91
91
  # @return [String] response as Markdown
92
92
  def command(command, argument=nil)
93
- response = Rodbot.request(command, query: { argument: argument })
94
- case response.code
95
- when 200 then response.body
93
+ case command
94
+ when 'ping' then 'pong'
95
+ when 'version' then "rodbot-#{Rodbot::VERSION}"
96
+ else request(command, argument)
97
+ end
98
+ end
99
+
100
+ # Perform the command on the app using a GET request
101
+ #
102
+ # @param command [String] command to perform
103
+ # @param argument [String, nil] optional arguments
104
+ # @return [String] response as Markdown
105
+ def request(command, argument=nil)
106
+ response = Rodbot.request(command, params: { argument: argument })
107
+ case response.status
108
+ when 200 then response.body.to_s
96
109
  when 404 then "[[SENDER]] I don't know what do do with `!#{command}`. 🤔"
97
110
  else fail
98
111
  end
@@ -1,7 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
3
  require 'readline'
4
- require 'httparty'
4
+ require 'httpx'
5
5
  require 'pastel'
6
6
  require 'tty-markdown'
7
7
 
@@ -16,6 +16,7 @@ module Rodbot
16
16
  # @param raw [Boolean] whether to display raw Markdown
17
17
  def initialize(sender, raw: false)
18
18
  @sender, @raw = sender, raw
19
+ @relay = Rodbot::Relay.new
19
20
  @pastel = Pastel.new
20
21
  end
21
22
 
@@ -33,17 +34,7 @@ module Rodbot
33
34
  def reply_to(message)
34
35
  return "(no command given)" unless message.match?(/^!/)
35
36
  command, argument = message[1..].split(/\s+/, 2)
36
- body = begin
37
- response = Rodbot.request(command, query: { argument: argument })
38
- case response.code
39
- when 200 then response.body
40
- when 404 then "[[SENDER]] I've never heard of `!#{command}`, try `!help` instead. 🤔"
41
- else fail
42
- end
43
- rescue
44
- "[[SENDER]] I'm having trouble talking to the app. 💣"
45
- end
46
- text_for body.psub(placeholders)
37
+ text_for @relay.send(:command, command, argument).psub(placeholders)
47
38
  end
48
39
 
49
40
  def placeholders
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rodbot
4
- VERSION = "0.3.1"
4
+ VERSION = "0.3.3"
5
5
  end
@@ -4,7 +4,7 @@ x-defaults: &defaults
4
4
  build:
5
5
  context: .
6
6
  dockerfile_inline: |
7
- FROM ruby:3.2-alpine
7
+ FROM ruby:[%= RUBY_VERSION.sub(/\.\d+$/, '') %]-alpine
8
8
  RUN apk update && apk --no-cache add build-base
9
9
  ENV RODBOT_ENV="production"
10
10
  ENV RACK_ENV="production"
@@ -4,7 +4,7 @@ x-defaults: &defaults
4
4
  build:
5
5
  context: .
6
6
  dockerfile_inline: |
7
- FROM ruby:3.2-alpine
7
+ FROM ruby:[%= RUBY_VERSION.sub(/\.\d+$/, '') %]-alpine
8
8
  RUN apk update && apk --no-cache add build-base
9
9
  ENV RODBOT_ENV="production"
10
10
  ENV RACK_ENV="production"
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ echo "--> Checking environment"
5
+ echo "RODBOT_ENV: $RODBOT_ENV"
6
+ echo "RODBOT_PLUGINS: $RODBOT_PLUGINS"
7
+
8
+ echo "--> Installing bundle"
9
+ bundle config set with $RODBOT_PLUGINS
10
+ bundle install
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env bash
2
+
3
+ export RODBOT_APP_HOST=0.0.0.0
4
+ bundle exec rodbot start
5
+ sleep infinity
@@ -0,0 +1,19 @@
1
+ services:
2
+ - type: web
3
+ name: bot
4
+ domains:
5
+ - bot.example.com # TODO: use a domain name of your own
6
+ runtime: ruby
7
+ buildCommand: render-build.sh
8
+ startCommand: render-start.sh
9
+ healthCheckPath: /healthz
10
+ autoDeploy: true
11
+ envVars:
12
+ - key: PORT
13
+ value: 7200
14
+ - key: PRODUCTION_CREDENTIALS_KEY
15
+ value:
16
+ - key: RODBOT_ENV
17
+ value: production
18
+ - key: RODBOT_PLUGINS
19
+ value: matrix # TODO: update space separated list of plugins
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ echo "--> Checking environment"
5
+ echo "RODBOT_ENV: $RODBOT_ENV"
6
+ echo "RODBOT_PLUGINS: $RODBOT_PLUGINS"
7
+
8
+ echo "--> Installing bundle"
9
+ bundle config set with $RODBOT_PLUGINS
10
+ bundle install
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env bash
2
+
3
+ case 1 in
4
+ "app")
5
+ export RODBOT_APP_HOST=0.0.0.0
6
+ bundle exec rodbot start app
7
+ ;;
8
+ "relay")
9
+ bundle exec rodbot start relay
10
+ ;;
11
+ "schedule")
12
+ bundle exec rodbot start schedule
13
+ ;;
14
+ *)
15
+ echo "Invalid argument"
16
+ exit 1
17
+ ;;
18
+ esac
@@ -0,0 +1,42 @@
1
+ services:
2
+ - type: web
3
+ name: bot-app
4
+ domains:
5
+ - bot.example.com # TODO: use a domain name of your own
6
+ runtime: ruby
7
+ buildCommand: render-build.sh
8
+ startCommand: render-start.sh app
9
+ healthCheckPath: /healthz
10
+ autoDeploy: true
11
+ envVars:
12
+ - fromGroup: bot
13
+ - key: PORT
14
+ value: 7200
15
+ - type: worker
16
+ name: bot-relay
17
+ runtime: ruby
18
+ buildCommand: render-build.sh
19
+ startCommand: render-start.sh relay
20
+ autoDeploy: true
21
+ envVars:
22
+ - fromGroup: bot
23
+ - type: worker
24
+ name: bot-schedule
25
+ runtime: ruby
26
+ buildCommand: render-build.sh
27
+ startCommand: render-start.sh schedule
28
+ autoDeploy: true
29
+ envVars:
30
+ - fromGroup: bot
31
+
32
+ envVarGroups:
33
+ - name: bot
34
+ envVars:
35
+ - key: PRODUCTION_CREDENTIALS_KEY
36
+ value:
37
+ - key: RODBOT_ENV
38
+ value: production
39
+ - key: RODBOT_PLUGINS
40
+ value: "matrix" # TODO: update space separated list of plugins
41
+ - key: RODBOT_APP_URL
42
+ value: https://bot.example.com # TODO: use the above service domain name
@@ -0,0 +1 @@
1
+ [%= RUBY_VERSION.sub(/\.\d+$/, '') %]
@@ -7,5 +7,6 @@ class App < Roda
7
7
  r.root { view :root }
8
8
  end
9
9
 
10
+ run :healthz, Routes::Healthz
10
11
  run :help, Routes::Help
11
12
  end
@@ -0,0 +1,15 @@
1
+ module Routes
2
+ class Healthz < App
3
+
4
+ route do |r|
5
+
6
+ # GET /healthz
7
+ r.root do
8
+ response['Content-Type'] = 'text/plain; charset=utf-8'
9
+ 'alive and kicking'
10
+ end
11
+
12
+ end
13
+
14
+ end
15
+ end
data/rodbot.gemspec CHANGED
@@ -46,7 +46,7 @@ Gem::Specification.new do |spec|
46
46
  spec.add_runtime_dependency 'dry-credentials', '~> 0'
47
47
  spec.add_runtime_dependency 'tty-markdown', '~> 0'
48
48
  spec.add_runtime_dependency 'pastel', '~> 0'
49
- spec.add_runtime_dependency 'httparty', '~> 0'
49
+ spec.add_runtime_dependency 'httpx', '~> 1'
50
50
  spec.add_runtime_dependency 'puma', '~> 6', '>= 6.2'
51
51
  spec.add_runtime_dependency 'roda', '~> 3'
52
52
  spec.add_runtime_dependency 'tilt', '~> 2'
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rodbot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sven Schwyn
@@ -29,7 +29,7 @@ cert_chain:
29
29
  kAyiRqgxF4dJviwtqI7mZIomWL63+kXLgjOjMe1SHxfIPo/0ji6+r1p4KYa7o41v
30
30
  fwIwU1MKlFBdsjkd
31
31
  -----END CERTIFICATE-----
32
- date: 2023-10-11 00:00:00.000000000 Z
32
+ date: 2023-10-21 00:00:00.000000000 Z
33
33
  dependencies:
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: zeitwerk
@@ -102,19 +102,19 @@ dependencies:
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  - !ruby/object:Gem::Dependency
105
- name: httparty
105
+ name: httpx
106
106
  requirement: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: '1'
111
111
  type: :runtime
112
112
  prerelease: false
113
113
  version_requirements: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '0'
117
+ version: '1'
118
118
  - !ruby/object:Gem::Dependency
119
119
  name: puma
120
120
  requirement: !ruby/object:Gem::Requirement
@@ -451,6 +451,8 @@ files:
451
451
  - checksums/rodbot-0.2.0.gem.sha512
452
452
  - checksums/rodbot-0.3.0.gem.sha512
453
453
  - checksums/rodbot-0.3.1.gem.sha512
454
+ - checksums/rodbot-0.3.2.gem.sha512
455
+ - checksums/rodbot-0.3.3.gem.sha512
454
456
  - doc/rodbot.afphoto
455
457
  - doc/rodbot.avif
456
458
  - exe/rodbot
@@ -509,12 +511,17 @@ files:
509
511
  - lib/templates/deploy/docker/compose.yaml.gerb
510
512
  - lib/templates/deploy/procfile-split/Procfile.gerb
511
513
  - lib/templates/deploy/procfile/Procfile.gerb
514
+ - lib/templates/deploy/render-split/render-build.sh
515
+ - lib/templates/deploy/render-split/render-start.sh
512
516
  - lib/templates/deploy/render-split/render.yaml.gerb
517
+ - lib/templates/deploy/render/render-build.sh
518
+ - lib/templates/deploy/render/render-start.sh
513
519
  - lib/templates/deploy/render/render.yaml.gerb
514
520
  - lib/templates/new/.gitignore
515
- - lib/templates/new/.ruby-version
521
+ - lib/templates/new/.ruby-version.gerb
516
522
  - lib/templates/new/README.md
517
523
  - lib/templates/new/app/app.rb
524
+ - lib/templates/new/app/routes/healthz.rb
518
525
  - lib/templates/new/app/routes/help.rb
519
526
  - lib/templates/new/app/views/layout.erb
520
527
  - lib/templates/new/app/views/root.erb
@@ -563,7 +570,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
563
570
  - !ruby/object:Gem::Version
564
571
  version: '0'
565
572
  requirements: []
566
- rubygems_version: 3.4.20
573
+ rubygems_version: 3.4.21
567
574
  signing_key:
568
575
  specification_version: 4
569
576
  summary: Minimalistic framework to build chat bots on top of a Roda backend
metadata.gz.sig CHANGED
Binary file
@@ -1 +0,0 @@
1
- 3.2