nagare-redis 0.1.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97ba30f65c114767427c1fe42b8558585e3bd4e767aa58b21300472a12787e06
4
- data.tar.gz: 32e945230c09fa0a903ac34afd08a5e624ad579c2386841bbe0081b415a0f7ea
3
+ metadata.gz: a74be4520fe261310cc782a2232ad5270ed572c4afbd98072241ef6dc1bc118c
4
+ data.tar.gz: f3d9391aae29591f9652e342034ce79959498a020596b01a4d4c3d40bf35d33a
5
5
  SHA512:
6
- metadata.gz: f283a8b1348c26c58e6d78f3dab2ad03ff6c70da1424826dab9fe539fb4b633b9205942ae10eb702181ac82ad2b7cf08d3da05134189ec9e508623acd0e586ad
7
- data.tar.gz: 5e9ce639ab272a002955bf414b51034703238a7f364bb958bf2ff0c8e5dffccb607a8920f06df76f0afa593c77fc9ca7312ea95c1b1c651b0c052ad1941f22a6
6
+ metadata.gz: b9c5c5bfa26746f5a0d5c84446991aad2d3d3faf802e8c9222d61fb79b6f2aaecdf55b81654ec71571c5d978d1350bb8306c054db2e816106c9a730383c2b9e6
7
+ data.tar.gz: a973dc7583907a0b75d0c8e09dda57e799721eab302a3d1786e0c83293c1475baa37cbea8ccc3dbb36fd39a45e4c906bac33dea2b4980a36c7a733b7a919f96f
@@ -0,0 +1,43 @@
1
+ name: release
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ jobs:
9
+ release-please:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: GoogleCloudPlatform/release-please-action@v2
13
+ id: release
14
+ with:
15
+ release-type: ruby
16
+ package-name: nagare-redis
17
+ bump-minor-pre-major: true
18
+ version-file: "lib/nagare/version.rb"
19
+ # Checkout code if release was created
20
+ - uses: actions/checkout@v2
21
+ if: ${{ steps.release.outputs.release_created }}
22
+ # Setup ruby if a release was created
23
+ - uses: ruby/setup-ruby@v1
24
+ with:
25
+ ruby-version: 2.6.8
26
+ if: ${{ steps.release.outputs.release_created }}
27
+ # Bundle install
28
+ - run: bundle install
29
+ if: ${{ steps.release.outputs.release_created }}
30
+ # Publish
31
+ - name: publish gem
32
+ run: |
33
+ mkdir -p $HOME/.gem
34
+ touch $HOME/.gem/credentials
35
+ chmod 0600 $HOME/.gem/credentials
36
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
37
+ gem build *.gemspec
38
+ gem push *.gem
39
+ env:
40
+ # Make sure to update the secret name
41
+ # if yours isn't named RUBYGEMS_AUTH_TOKEN
42
+ GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
43
+ if: ${{ steps.release.outputs.release_created }}
@@ -15,9 +15,9 @@ jobs:
15
15
  - uses: actions/checkout@v2
16
16
 
17
17
  - name: Set up Ruby 2.6
18
- uses: actions/setup-ruby@v1
18
+ uses: ruby/setup-ruby@v1
19
19
  with:
20
- ruby-version: 2.6.6
20
+ ruby-version: 2.6.8
21
21
 
22
22
  - uses: actions/cache@v1
23
23
  with:
data/CHANGELOG.md ADDED
@@ -0,0 +1,22 @@
1
+ # Changelog
2
+
3
+ ## [0.4.0](https://www.github.com/vavato-be/nagare/compare/v0.3.0...v0.4.0) (2021-07-13)
4
+
5
+
6
+ ### Features
7
+
8
+ * Increment version number automaticaly on release ([fe5f181](https://www.github.com/vavato-be/nagare/commit/fe5f1816f65869d1ecba04ee34c4eb290e2823d4))
9
+
10
+ ## [0.3.0](https://www.github.com/vavato-be/nagare/compare/v0.2.0...v0.3.0) (2021-07-13)
11
+
12
+
13
+ ### Features
14
+
15
+ * document release process ([eb973e5](https://www.github.com/vavato-be/nagare/commit/eb973e526156dfa89344671060044e6d8560e0e6))
16
+
17
+ ## [0.2.0](https://www.github.com/vavato-be/nagare/compare/v0.1.2...v0.2.0) (2021-07-13)
18
+
19
+
20
+ ### Features
21
+
22
+ * create PR for release after merge on main ([f562d62](https://www.github.com/vavato-be/nagare/commit/f562d6216e45b63d1594a425b04faca3acad8857))
data/Gemfile CHANGED
@@ -4,4 +4,5 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  gem 'rake', '~> 12.0'
7
+ gem 'redis', github: 'vavato-be/redis-rb'
7
8
  gem 'rspec', '~> 3.0'
data/Gemfile.lock CHANGED
@@ -1,22 +1,27 @@
1
+ GIT
2
+ remote: https://github.com/vavato-be/redis-rb.git
3
+ revision: 79f36a58e69beb72f3bcef2ae584b30324fa2f07
4
+ specs:
5
+ redis (6.2.0)
6
+
1
7
  PATH
2
8
  remote: .
3
9
  specs:
4
- nagare-redis (0.1.3)
5
- redis (~> 4.1, >= 4.1.0)
10
+ nagare-redis (0.3.0)
11
+ redis (~> 6.2, >= 6.2.0)
6
12
 
7
13
  GEM
8
14
  remote: https://rubygems.org/
9
15
  specs:
10
- ast (2.4.1)
16
+ ast (2.4.2)
11
17
  diff-lcs (1.3)
12
- parallel (1.19.2)
13
- parser (2.7.1.4)
18
+ parallel (1.20.1)
19
+ parser (3.0.2.0)
14
20
  ast (~> 2.4.1)
15
21
  rainbow (3.0.0)
16
22
  rake (12.3.2)
17
- redis (4.2.1)
18
- regexp_parser (1.7.1)
19
- rexml (3.2.4)
23
+ regexp_parser (2.1.1)
24
+ rexml (3.2.5)
20
25
  rspec (3.9.0)
21
26
  rspec-core (~> 3.9.0)
22
27
  rspec-expectations (~> 3.9.0)
@@ -30,21 +35,22 @@ GEM
30
35
  diff-lcs (>= 1.2.0, < 2.0)
31
36
  rspec-support (~> 3.9.0)
32
37
  rspec-support (3.9.3)
33
- rubocop (0.88.0)
38
+ rubocop (1.18.3)
34
39
  parallel (~> 1.10)
35
- parser (>= 2.7.1.1)
40
+ parser (>= 3.0.0.0)
36
41
  rainbow (>= 2.2.2, < 4.0)
37
- regexp_parser (>= 1.7)
42
+ regexp_parser (>= 1.8, < 3.0)
38
43
  rexml
39
- rubocop-ast (>= 0.1.0, < 1.0)
44
+ rubocop-ast (>= 1.7.0, < 2.0)
40
45
  ruby-progressbar (~> 1.7)
41
- unicode-display_width (>= 1.4.0, < 2.0)
42
- rubocop-ast (0.2.0)
43
- parser (>= 2.7.0.1)
44
- rubocop-rspec (1.42.0)
45
- rubocop (>= 0.87.0)
46
- ruby-progressbar (1.10.1)
47
- unicode-display_width (1.7.0)
46
+ unicode-display_width (>= 1.4.0, < 3.0)
47
+ rubocop-ast (1.7.0)
48
+ parser (>= 3.0.1.1)
49
+ rubocop-rspec (2.4.0)
50
+ rubocop (~> 1.0)
51
+ rubocop-ast (>= 1.1.0)
52
+ ruby-progressbar (1.11.0)
53
+ unicode-display_width (2.0.0)
48
54
 
49
55
  PLATFORMS
50
56
  ruby
@@ -52,9 +58,10 @@ PLATFORMS
52
58
  DEPENDENCIES
53
59
  nagare-redis!
54
60
  rake (~> 12.0)
61
+ redis!
55
62
  rspec (~> 3.0)
56
- rubocop (~> 0.88, >= 0.88)
57
- rubocop-rspec (~> 1.42, >= 1.42.0)
63
+ rubocop (~> 1.18.3, >= 1.18.3)
64
+ rubocop-rspec (~> 2.4.0, >= 2.4.0)
58
65
 
59
66
  BUNDLED WITH
60
67
  2.1.0
data/README.md CHANGED
@@ -40,20 +40,25 @@ To use with rails, add nagare to the initializers:
40
40
  #### config/initializers/nagare.rb
41
41
  ```ruby
42
42
  Nagare.configure do |config|
43
- # After x seconds a consumer is considered dead and its messages
44
- # are assigned to a different consumer in the group. Configuring
43
+ # After x milisseconds a pending message is considered failed and
44
+ # gets retried by a different consumer in the group. Configuring
45
45
  # it too low might cause double processing of messages as a consumer
46
46
  # "steals" the load of another while the first one is still processing
47
47
  # it and hasn't had the chance to ACK, configuring it too high will
48
48
  # introduce latency in your processing.
49
- # Default: 300 (5 minutes)
50
- config.dead_consumer_timeout = 600
49
+ # Default: 600.000 (10 minutes)
50
+ config.min_idle_time = 600_0000
51
51
 
52
52
  # This is the consumer group name that will be used or created in
53
53
  # Redis. Use a different group for every microservice / application
54
54
  # Default: Rails.env
55
55
  config.group_name = :monolith
56
56
 
57
+ # A suffix is supported in order to separate different environments
58
+ # within the same redis database. Useful for development/test. This
59
+ # gets added automatically to stream names and consumer group names.
60
+ config.suffix = ''
61
+
57
62
  # URL to connect to redis. Defaults to redis://localhost:6379 uses
58
63
  # ENV['REDIS_URL'] if present.
59
64
  config.redis_url = 'redis://10.1.1.1:6379'
@@ -62,6 +67,19 @@ Nagare.configure do |config|
62
67
  # and in the background
63
68
  # Default: 3 threads
64
69
  config.threads = 3
70
+
71
+ # Nagare can execute a proc for error handling. This enables you to
72
+ # use APM tools like New Relic or Appsignal with it.
73
+ # The proc takes 2 parameters, message and error.
74
+ # By default, nagare logs the error to stderr.
75
+ config.error_handler = proc do |message, error|
76
+ Appsignal.set_error(error);
77
+ end
78
+
79
+ # After exceeding the maximum number of retries, nagare moves the
80
+ # failing messages to a Dead Letter Queue stream.
81
+ # By default this stream is named 'dlq', but you can customize it.
82
+ config.dlq_stream = 'its_dead_jim'
65
83
  end
66
84
  ```
67
85
 
@@ -106,7 +124,7 @@ end
106
124
 
107
125
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
108
126
 
109
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
127
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). A merge to the `main` branch will automatically open a PR to release a new version of nagare. Merging that PR will release to rubygems.
110
128
 
111
129
  ## Contributing
112
130
 
data/exe/nagare CHANGED
@@ -2,8 +2,8 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  if File.exist?('config/environment.rb')
5
- # Load rails env if inside a rails appa
6
- require_relative '../config/environment'
5
+ # Load rails env if inside a rails app
6
+ require_relative File.join(Dir.pwd, 'config', 'environment')
7
7
  elsif File.exist?('Gemfile.lock')
8
8
  # Load bundler context if using bundler
9
9
  require 'bundler/setup'
data/lib/nagare/config.rb CHANGED
@@ -5,13 +5,14 @@ module Nagare
5
5
  # See the README for possible values and what they do
6
6
  class Config
7
7
  class << self
8
- attr_accessor :dead_consumer_timeout, :group_name, :redis_url, :threads,
9
- :suffix
8
+ attr_accessor :group_name, :redis_url, :threads, :suffix, :min_idle_time,
9
+ :error_handler, :dlq_stream, :max_retries
10
10
 
11
11
  # Runs code in the block passed in to configure Nagare and sets defaults
12
12
  # when values are not set.
13
13
  #
14
- # returns Nagare::Config self
14
+ # returns [Nagare::Config] self
15
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/AbcSize
15
16
  def configure
16
17
  yield(self)
17
18
  @dead_consumer_timeout ||= 5000
@@ -19,8 +20,17 @@ module Nagare
19
20
  @redis_url = redis_url || ENV['REDIS_URL'] || 'redis://localhost:6379'
20
21
  @threads ||= 1
21
22
  @suffix ||= nil
23
+ @min_idle_time ||= 600_000
24
+ @error_handler ||= proc do |message, error|
25
+ Nagare.logger.error "Failed to process message #{message}"
26
+ Nagare.logger.error error.message
27
+ Nagare.logger.error error.backtrace.join("\n")
28
+ end
29
+ @dlq_stream ||= 'dlq'
30
+ @max_retries ||= 10
22
31
  self
23
32
  end
33
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/AbcSize
24
34
  end
25
35
  end
26
36
  end
@@ -43,6 +43,7 @@ module Nagare
43
43
  # The ClassMethods module is automatically loaded into child classes
44
44
  # effectively adding the `stream` class method to the child class.`
45
45
  def self.inherited(subclass)
46
+ super
46
47
  subclass.extend(ClassMethods)
47
48
  end
48
49
 
@@ -59,8 +59,13 @@ module Nagare
59
59
  private
60
60
 
61
61
  def poll_stream(stream, listeners)
62
- # TODO: Use thread pool
63
- messages = Nagare::RedisStreams.read_next_messages(stream, group)
62
+ return unless Nagare::RedisStreams.group_exists?(stream, group)
63
+
64
+ messages = Nagare::RedisStreams.claim_next_stuck_message(stream, group)
65
+
66
+ if messages.nil? || messages.empty?
67
+ messages = Nagare::RedisStreams.read_next_messages(stream, group)
68
+ end
64
69
  return unless messages.any?
65
70
 
66
71
  messages.each do |message|
@@ -68,17 +73,18 @@ module Nagare
68
73
  end
69
74
  end
70
75
 
76
+ def claim_pending_messages(stream)
77
+ return nil unless Nagare::RedisStreams.group_exists?(stream, group)
78
+ end
79
+
71
80
  def deliver_message(stream, message, listeners)
72
81
  listener_failed = false
73
82
 
74
83
  listeners.each do |listener|
75
84
  invoke_listener(stream, message, listener)
76
85
  rescue StandardError => e
77
- # TODO: Retry logic
78
- logger.error e.message
79
- logger.error e.backtrace.join("\n")
80
86
  listener_failed = true
81
- # TODO: Notify Appsignal
87
+ Nagare::Config.error_handler.call(message, e)
82
88
  end
83
89
 
84
90
  return if listener_failed
@@ -30,7 +30,6 @@ module Nagare
30
30
  # @param group [String] name of the group
31
31
  #
32
32
  # @return [Boolean] true if the group exists, otherwise false
33
- # rubocop:disable Metrics/AbcSize
34
33
  def group_exists?(stream, group)
35
34
  stream = stream_name(stream)
36
35
  info = connection.xinfo(:groups, stream.to_s)
@@ -41,7 +40,6 @@ module Nagare
41
40
  logger.info e.backtrace.join("\n")
42
41
  false
43
42
  end
44
- # rubocop:enable Metrics/AbcSize
45
43
 
46
44
  ##
47
45
  # Creates a group in redis for the stream using xgroup
@@ -78,7 +76,63 @@ module Nagare
78
76
  # @return [String] message id
79
77
  def publish(stream, event_name, data)
80
78
  stream = stream_name(stream)
81
- connection.xadd(stream, { "#{event_name}": data })
79
+ connection.xadd(stream, { "#{event_name}": data.to_json })
80
+ end
81
+
82
+ ##
83
+ # Claums the next message of the consumer group that is stuck
84
+ # (pending and past min_idle_time since being picked up)
85
+ #
86
+ # @param stream_prefix [String] name of the stream
87
+ # @param group [String] name of the consumer group
88
+ #
89
+ # @return [Array[Hash]] array containing the 1 message or empty
90
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
91
+ def claim_next_stuck_message(stream_prefix, group)
92
+ stream = stream_name(stream_prefix)
93
+ result = connection.xautoclaim(stream,
94
+ "#{stream}-#{group}",
95
+ "#{hostname}-#{thread_id}",
96
+ Nagare::Config.min_idle_time,
97
+ '0-0',
98
+ count: 1)
99
+
100
+ # Move message to DLQ if retried too much and get next one
101
+ if result['entries'].any?
102
+ message_id = result['entries'].first.first
103
+ if retry_count(stream_prefix, group,
104
+ message_id) > Nagare::Config.max_retries
105
+ move_to_dlq(stream_prefix, group, result['entries'].first)
106
+ return claim_next_stuck_message(stream, group)
107
+ end
108
+ end
109
+
110
+ result['entries'] || []
111
+ end
112
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
113
+
114
+ ##
115
+ # Uses XPENDING to verify the number of times the message was
116
+ # delivered
117
+ def retry_count(stream, group, message_id)
118
+ stream = stream_name(stream)
119
+ result = connection.xpending(stream,
120
+ "#{stream}-#{group}",
121
+ message_id,
122
+ message_id,
123
+ 1)
124
+ return 0 unless result.any?
125
+
126
+ result.first['count']
127
+ end
128
+
129
+ ##
130
+ # Moves a message to the dead letter queue stream
131
+ def move_to_dlq(stream, group, message)
132
+ Nagare.logger.warn "Moving message to DLQ #{message} \
133
+ from stream #{stream}"
134
+ publish(Nagare::Config.dlq_stream, stream, message)
135
+ mark_processed(stream, group, message.first)
82
136
  end
83
137
 
84
138
  ##
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rubocop:disable
3
4
  module Nagare
4
- VERSION = '0.1.3'
5
+ # Needs to be double quotes for release-please ruby updater
6
+ # see https://github.com/googleapis/release-please/blob/master/src/updaters/version-rb.ts
7
+ #
8
+ # rubocop:disable Style/StringLiterals
9
+ VERSION = "0.5.0"
10
+ # rubocop:enable Style/StringLiterals
5
11
  end
data/nagare.gemspec CHANGED
@@ -20,14 +20,16 @@ Gem::Specification.new do |spec|
20
20
  spec.metadata['source_code_uri'] = 'https://github.com/vavato-be/nagare.git'
21
21
  spec.metadata['changelog_uri'] = 'https://github.com/vavato-be/nagare/CHANGELOG.md'
22
22
 
23
- spec.add_dependency 'redis', '~> 4.1', '>= 4.1.0'
24
- spec.add_development_dependency 'rubocop', '~> 0.88', '>= 0.88'
25
- spec.add_development_dependency 'rubocop-rspec', '~> 1.42', '>= 1.42.0'
23
+ spec.add_dependency 'redis', '~> 6.2', '>= 6.2.0'
24
+ spec.add_development_dependency 'rubocop', '~> 1.18.3', '>= 1.18.3'
25
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.4.0', '>= 2.4.0'
26
26
 
27
27
  # Specify which files should be added to the gem when it is released.
28
28
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
29
29
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
30
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
30
+ `git ls-files -z`.split("\x0").reject do |f|
31
+ f.match(%r{^(test|spec|features)/})
32
+ end
31
33
  end
32
34
  spec.bindir = 'exe'
33
35
  spec.executables << 'nagare'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nagare-redis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Reis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-13 00:00:00.000000000 Z
11
+ date: 2021-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -16,60 +16,60 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.1.0
19
+ version: 6.2.0
20
20
  - - "~>"
21
21
  - !ruby/object:Gem::Version
22
- version: '4.1'
22
+ version: '6.2'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 4.1.0
29
+ version: 6.2.0
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '4.1'
32
+ version: '6.2'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: rubocop
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: '0.88'
39
+ version: 1.18.3
40
40
  - - "~>"
41
41
  - !ruby/object:Gem::Version
42
- version: '0.88'
42
+ version: 1.18.3
43
43
  type: :development
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
46
46
  requirements:
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- version: '0.88'
49
+ version: 1.18.3
50
50
  - - "~>"
51
51
  - !ruby/object:Gem::Version
52
- version: '0.88'
52
+ version: 1.18.3
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: rubocop-rspec
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
57
  - - ">="
58
58
  - !ruby/object:Gem::Version
59
- version: 1.42.0
59
+ version: 2.4.0
60
60
  - - "~>"
61
61
  - !ruby/object:Gem::Version
62
- version: '1.42'
62
+ version: 2.4.0
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: 1.42.0
69
+ version: 2.4.0
70
70
  - - "~>"
71
71
  - !ruby/object:Gem::Version
72
- version: '1.42'
72
+ version: 2.4.0
73
73
  description: Nagare is a wrapper around Redis Streams that enables event-driven architectures
74
74
  and pub/sub messaging withdurable subscribers
75
75
  email:
@@ -79,10 +79,12 @@ executables:
79
79
  extensions: []
80
80
  extra_rdoc_files: []
81
81
  files:
82
+ - ".github/workflows/release.yml"
82
83
  - ".github/workflows/run-tests.yml"
83
84
  - ".gitignore"
84
85
  - ".rspec"
85
86
  - ".rubocop.yml"
87
+ - CHANGELOG.md
86
88
  - CODE_OF_CONDUCT.md
87
89
  - Gemfile
88
90
  - Gemfile.lock